Update Successfully but Data not update in db. Django rest framework - django-models

I'm working on my final year project, and I need some help to understand what is actually happening, The problem is that: I hit the Update request through postman which gives the successful message for updating the data. but when I check my Database there is no updated data. I also did the debugging but there was no exception by which I can understand the problem Anyone can please help me?
I'm using
PgAdmin for my database.
Django==4.0.2
djangorestframework==3.13.1
djangorestframework-jwt==1.11.0
djangorestframework-simplejwt==5.0.0
psycopg2==2.9.3**.
My Models:
class Company(Base):
company_name = models.CharField(max_length=255, db_column='Company_Name')
company_email = models.EmailField(unique=True, max_length=255, db_column='company_email')
company_manager_name = models.CharField(max_length=255, db_column='Manager_Name')
company_address = models.CharField(max_length=255, db_column='Company_address')
about_company = models.TextField()
company_website = models.URLField(max_length=200)
is_active = models.BooleanField(default=True, db_column='IsActive', help_text='I will use this for enable/disable '
'a specific record')
class Meta:
db_table: 'Company'
def __str__(self):
return self.company_name
def save(self, *args, **kwargs):
try:
if not self.pk:
self.company_email = self.company_email.replace(" ", "").lower()
super().save()
except Exception:
raise
class Base(models.Model):
"""Following fields are abstract and will be use in All over the project Any time Anywhere"""
create_by = models.BigIntegerField(db_column='CreatedBy', null=True, blank=True, default=0)
create_on = models.DateTimeField(db_column='CreatedOn', auto_now_add=True)
modified_by = models.BigIntegerField(db_column='ModifiedBy', null=True, blank=True, default=0)
modified_on = models.DateTimeField(db_column='ModifiedOn', auto_now=True)
deleted_by = models.BigIntegerField(db_column='DeletedBy', null=True, blank=True, default=0)
deleted_on = models.DateTimeField(db_column='DeletedOn', auto_now=True)
status = models.BigIntegerField(db_column='Status', default=0, help_text='I will use this field for making'
'the status like pending approved and '
'for some other purpose by Default it is '
'Zero which has no meaning', )
class Meta:
abstract: True
serializer.py:
class CompanyUpdateSerializer(serializers.ModelSerializer):
company_name = serializers.CharField(required=True, allow_null=False, allow_blank=False)
company_email = serializers.CharField(required=True, allow_null=False, allow_blank=False)
company_manager_name = serializers.CharField(required=True, allow_null=False, allow_blank=False)
company_address = serializers.CharField(required=True, allow_null=False, allow_blank=False)
about_company = serializers.CharField(required=True, allow_null=False, allow_blank=False)
company_website = serializers.URLField(allow_blank=False, allow_null=False)
class Meta:
model = Company
fields = ['id', 'company_name', 'company_email', 'company_manager_name', 'company_address', 'about_company',
'company_website']
def update(self, instance, validated_data):
try:
instance.company_name = validated_data.get('company_name', instance.company_name)
instance.company_email = validated_data.get('company_email', instance.company_email)
instance.company_manager_name = validated_data.get('company_manager_name', instance.company_manager_name)
instance.company_address = validated_data.get('company_address', instance.company_address)
instance.about_company = validated_data.get('about_company', instance.about_company)
instance.company_website = validated_data.get('company_website', instance.company_website)
instance.save()
return instance
except Exception as e:
raise e
Views.py
def put(self, request, pk=None):
try:
id1 = pk
saved_company = Company.objects.get(pk=id1)
data = request.data
serializer = CompanyUpdateSerializer(instance=saved_company, data=data)
if serializer.is_valid():
serializer.save()
return self.send_response(success=True, code=f'200', status_code=status.HTTP_200_OK,
description='Company is updated')
return self.send_response(code=f'422', status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
description=serializer.errors)
except ObjectDoesNotExist:
return self.send_response(code='422', status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
description="No Company matches the given query.")
except IntegrityError:
return self.send_response(code=f'422', status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
description="Email Already Exist")
except Company.DoesNotExist:
return self.send_response(code=f'422', status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
description="Company Model doesn't exists")
except FieldError:
return self.send_response(code=f'500', description="Cannot resolve keyword given in 'order_by' into field")
except Exception as e:
return self.send_response(code=f'500', description=e)

The problem comes from Company.save() method.
You overrode it as
class Company(Base):
...
def save(self, *args, **kwargs):
try:
if not self.pk:
self.company_email = self.company_email.replace(" ", "").lower()
super().save()
except Exception:
raise
Notice the call of super().save() inside the self.pk is None if statement block.
This will make the actual save method to be called only when the pk is None, meaning that only when a new instance is created, not when an instance is updated.
Moving the super().save() call to be outside the if statement should handle both creating and updating.
class Company(Base):
...
def save(self, *args, **kwargs):
try:
if not self.pk:
self.company_email = self.company_email.replace(" ", "").lower()
super().save(*args, **kwargs)
except Exception:
raise

Related

TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use technicians.set() instead

I keep getting this very same type error even though I am using set. Can someone maybe point out what I'm doing wrong in my api endpoint?
views.py
#require_http_methods(["GET", "POST"])
def api_requerimientos(request):
if request.method == "GET":
requerimientos = FormularioCliente.objects.all()
return JsonResponse(
{"requerimientos": requerimientos},
encoder=FormularioClienteEncoder,
)
elif request.method == "POST":
print("POST REQUEST HIT")
try:
content = json.loads(request.body)
except json.JSONDecodeError:
return HttpResponseBadRequest("Invalid JSON in request body")
requerimiento = FormularioCliente(**content) # Create a new FormularioCliente object
if "technicians" in content and isinstance(content["technicians"], list):
try:
technicians_id_list = content["technicians"]
technicians = Technician.objects.filter(employee_number__in=technicians_id_list)
requerimiento.technicians.set(technicians)
requerimiento.save()
print('requerimiento:', requerimiento)
except Technician.DoesNotExist:
pass
requerimiento.save() # Save the object to the database
models.py
class FormularioCliente(models.Model):
empresa = models.CharField(max_length=21, null=True, unique=True)
titulo = models.CharField(max_length=66)
descripcion = models.CharField(max_length=66)
enlace = models.URLField(null=True)
tipo = models.CharField(max_length=17, choices=TIPO_REQUIRIMIENTO, default="tecnologia")
date = models.DateField(null=True, auto_now_add=True)
time = models.TimeField(null=True, auto_now_add=True)
entrega = models.DateField(null=True)
finished = models.CharField(max_length=19, choices=TIPO_FINALIZACION, default="Abierto")
technicians = models.ManyToManyField(Technician, blank=True)
special_hours = models.SmallIntegerField(default=0)
regular_hours = models.PositiveSmallIntegerField(default=1)
total_hours = models.SmallIntegerField(default=1)
importancia = models.PositiveSmallIntegerField(default=1)
file = models.FileField(upload_to='files', blank=True)
updated = models.DateField(auto_now=True)
def __str__(self):
return f'{self.titulo}: {self.descripcion} # {self.date}'
def technicians_as_json(self):
return list(self.technicians.all().values())
class Technician(models.Model):
name = models.TextField()
employee_number = models.SmallIntegerField(unique=True, primary_key=True)
def __str__(self):
return self.name + " - " + str(self.employee_number)
encoders.py
class TechnicianEncoder(ModelEncoder):
model = Technician
properties = ["name", "employee_number"]
class FormularioClienteEncoder(ModelEncoder):
model = FormularioCliente
properties = [
"id",
"empresa",
"titulo",
"descripcion",
# "user",
"enlace",
# "tipo",
# "File",
"tipo",
"date",
"time",
"entrega",
"finished",
"technicians", # <-- Add this
"special_hours",
"regular_hours",
"total_hours",
"importancia",
"updated",
]
encoders = {"technicians": TechnicianEncoder()}
I also tried to loop through technicians queryset and add it to the instance one by one as well via the add() method but that also didn't work.
I even tried this:
techs = list(requerimiento.technicians.filter(employee_number__in=technicians_id_list).all())
requerimiento.technicians.set(techs)
None of it worked

Model field not updating in save()

In my Django MyModel I've created a new field last_status_change (a timestamp). Should be updated when that status changes.
However, even when a print shows that last_status_change is computed correctly, it doesn't get saved.
Is any field modification prohibited within save? What's the reason behind it? How to work around it?
class MyModel(models.Model):
first_name = models.CharField(max_length=100, verbose_name='Name')
confirmation_status = models.CharField(
choices=CONFIRMATION_STATUS_CHOICES,
default='registered', max_length=20
)
last_status_change = models.DateTimeField(null=True, blank=True)
def save(self, *args, **kwargs):
if self.pk:
original = MyModel.objects.get(pk=self.pk)
if original.confirmation_status != self.confirmation_status:
last_status_change = datetime.now()
return super(MyModel, self).save(*args, **kwargs)
You need to assign it to the self object, so:
from django.utils import timezone
class MyModel(models.Model):
first_name = models.CharField(max_length=100, verbose_name='Name')
confirmation_status = models.CharField(
choices=CONFIRMATION_STATUS_CHOICES, default='registered', max_length=20
)
last_status_change = models.DateTimeField(null=True, blank=True)
def save(self, *args, **kwargs):
if self.pk:
original = MyModel.objects.get(pk=self.pk)
if original.confirmation_status != self.confirmation_status:
self.last_status_change = timezone.now()
return super().save(*args, **kwargs)

Django - Query from a sub-table

I have an application that has a dropdown menu among other things.
The menu is created based on the requirements. I wrote a query that checks the statuses and calculates how many requirements are in a given status. Then he builds a menu out of it. However, I have a problem because sometimes a requisition has been created but no items have been added to it. In that case, my menu shows this as one of the items. This is not what he expects. I would like the query to return and count only those requirements in a given status that have children.
Below I paste the model code and inquiries.
class D_DemandStatus(ModelBaseClass):
status = models.CharField(max_length=20, unique=True)
name = models.CharField(max_length=50)
created_user = models.ForeignKey(User, on_delete=models.PROTECT)
def save(self, *args, **kwargs):
user = get_current_user()
if user and not user.pk:
user = None
if not self.pk:
self.created_user = user
self.modified_by = user
super(D_DemandStatus, self).save(*args, **kwargs)
def __str__(self):
return self.name
class Meta:
verbose_name = 'Demand status'
verbose_name_plural = 'Demands status'
class Demand(models.Model):
name = models.CharField(max_length=500)
status = models.ForeignKey(D_DemandStatus, default=3, on_delete=models.PROTECT, )
insert_user = models.ForeignKey(User, on_delete=models.PROTECT, editable=False)
insert_date = models.DateTimeField(default=datetime.datetime.now, editable=False)
def save(self, *args, **kwargs):
user = get_current_user()
if user and not user.pk:
user = None
if not self.pk:
self.insert_user = user
self.status = D_DemandStatus.objects.get(status='PREPARED')
self.modified_by = user
super(Demand, self).save(*args, **kwargs)
def __str__(self):
return self.name
def submitt(self, *args, **kwargs):
if self.pk :
dict_status = D_DemandStatus.objects.get(status='WAITING')
print(dict_status)
self.demanddetails_set.filter(demand_id = self.pk).update(status=dict_status)
self.status = dict_status
self.save()
def status_actualize(self, *args, **kwargs):
if self.pk :
dict_status = D_DemandStatus.objects.get(status='ORDERED')
items_status = DemandDetails.objects.filter(demand=self.pk).values('status').distinct()
if len(items_status) == 1 and items_status[0]['status'] == dict_status.id :
self.status = D_DemandStatus.objects.get(status='ORDERED')
#elif len(items_status) > 1 :
# self.status = D_DemandStatus.objects.get(status='INPROGRESS')
self.save()
class Meta:
verbose_name = 'Demand'
verbose_name_plural = 'Demands'
class DemandDetails(models.Model):
demand = models.ForeignKey(Demand, on_delete=models.CASCADE, related_name='items')
component = models.ForeignKey(Component, on_delete=models.CASCADE)
order_item = models.ForeignKey(OrderItem, null=True, on_delete=models.PROTECT, editable=False, related_name='demand_details_item')
quantity = models.IntegerField(default=1)
comment = models.CharField(max_length=150, blank=True)
status = models.ForeignKey(D_DemandStatus, default=3, on_delete=models.PROTECT, )
insert_user = models.ForeignKey(User, on_delete=models.PROTECT, editable=False)
insert_date = models.DateTimeField(auto_now_add=True)
def quantityUpdate(self, val):
if self.pk :
self.quantity = val
self.save()
def save(self, *args, **kwargs):
user = get_current_user()
if user and not user.pk:
user = None
if not self.pk:
self.insert_user = user
self.status = D_DemandStatus.objects.get(status='PREPARED')
if not self.pk:
try:
super(DemandDetails, self).save(*args, **kwargs)
except IntegrityError as e:
obj = DemandDetails.objects.get(demand_id=self.demand_id, component_id=self.component_id)
obj.quantity = obj.quantity + 1
obj.save()
else:
super(DemandDetails, self).save(*args, **kwargs)
def __str__(self):
return self.demand.name
class Meta:
verbose_name = 'Demand detail'
verbose_name_plural = 'Demand details'
constraints = [
models.UniqueConstraint(fields=['demand_id', 'component_id'], name='epm - DemandDetail (demand, component)' )
]
The query that works now looks like this:
demand_list = Demand.objects.values('status__name', 'status__id', 'status__status').annotate(count=Count('status__name')).filter(Q(status__status='WAITING') | Q(status__status='PREPARED')).order_by('-status__name')
In this case, however, even if the demand is empty (no items added), it is counted as 1
So I have changed the code a little, but it doesn't work as I would like, because it also counts the individual elements of the demand - which is obvious, because the query returns the subsequent rows that are counted.
demand_list = Demand.objects.values('status__name', 'status__id', 'status__status').annotate(count=Count('status__name'), piece=Count('demanddetails')).filter(Q(piece__gte=1)).filter(Q(status__status='WAITING') | Q(status__status='PREPARED')).order_by('-status__name')
I need to write the query in such a way that I get a list of statuses with numbers of demands only which have derived elements in DemandDetails. If a Demand exists but has no derived elements then it is not taken into account - rather it is counted as 0. This is important because in the extreme case there may be only one Demand which is empty and then I want to have information about it in the menu but with the number 0.
I hope I have managed to write clearly what I chaie.
Please help me to create a suitable query.
Regards

Django Post request for many to many field ValueError

I am working on a post request in which the user chooses from a list of tags and makes combinations of tags. The combination of tags should then be posted. Nothing should get changed in the Tag table.
These are the models:
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
"""Return a human readable representation of the model instance."""
return self.name or ''
#property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Combination(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, null=True)
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, null=True)
tag_id = models.ManyToManyField(Tag, null=True)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
objects = models.Manager()
def __str__(self):
return str(self.tag_id) or ''
This is the serializer for Combination.
serializers.py
class CombinationSerializer(serializers.ModelSerializer):
tag_id = TagWithIdSerializer(many=True, required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Combination
depth = 1
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag_id', 'created', 'score')
def create(self, validated_data):
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
score = 0
tag_data = validated_data.pop('tag_id', None)
combination = Combination(
user=user,
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
created=datetime.now(),
score=score
)
combination.save()
for tag_object in tag_data[0]:
combination.tag_id.add(tag_object)
return combination
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag_id'] = TagWithIdSerializer(instance.tag_id.all(), many=True).data
return rep
I have tried posting the following JSON object to the database:
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [{"id": 2014077506, "name": "corwn","language": "en"}]
}
I am getting a ValueError: Field 'id' expected a number but got 'name'.
How can I fix this issue?
you need to provide tag id for each tag not all tag data,
Try like this
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [2014077506,2014077507]
}

How to make use of filter using ContentType to check if model instance is already present or not

I am trying to implement like functionality based on this . I want to restrict user to hit like on a event only once. But I am getting the following error. I have added full error details at bottom
Exception Type: AttributeError at /api/event/likes/create/
Exception Value: 'str' object has no attribute '_meta'
models.py
class ThumbsUpManager(models.Manager):
def create_by_model_type(self, model_type, slug, content, user, parent_obj=None):
model_qs = ContentType.objects.filter(model=model_type)
if model_qs.exists():
some_model = model_qs.first().model_class()
obj_qs = some_model.objects.filter(slug=slug)
if obj_qs.exists() and obj_qs.count() == 1:
instance = self.model()
instance.content = content
instance.user = user
instance.content_type = model_qs.first()
instance.object_id = obj_qs.first().id
if parent_obj:
instance.parent = parent_obj
instance.save()
return instance
return None
class Thumbsup(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE)
content = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=True)
objects = ThumbsUpManager()
class Meta:
ordering = ['-timestamp']
def __str__(self):
return str(self.user.username)
#property
def is_parent(self):
if self.parent is not None:
return False
return True
urls.py
urlpatterns = [
path('create/', ThumbsUpCreateAPIView.as_view(), name='create'),
]
view.py
class ThumbsUpCreateAPIView(CreateAPIView):
queryset = Thumbsup.objects.all()
permission_classes = [IsAuthenticated, ]
def get_serializer_class(self):
model_type = self.request.GET.get("type")
slug = self.request.GET.get("slug")
obj_qs = Thumbsup.objects.all()
print(obj_qs)
parent_id = self.request.GET.get("parent_id", None)
return create_thumbs_up_serializer(
model_type=model_type,
slug=slug,
parent_id=parent_id,
user=self.request.user
)
serializers.py
def create_thumbs_up_serializer(model_type=None, slug=None, parent_id=None, user=None):
class ThumbsUpCreateSerializer(ModelSerializer):
class Meta:
model = Thumbsup
fields = [
'id',
'content',
'timestamp',
]
def __init__(self, *args, **kwargs):
self.model_type = model_type
self.slug = slug
self.parent_obj = None
self.user = user
if parent_id:
parent_qs = Thumbsup.objects.filter(id=parent_id)
if parent_qs.exists() and parent_qs.count() == 1:
self.parent_obj = parent_qs.first()
return super(ThumbsUpCreateSerializer, self).__init__(*args, **kwargs)
def validate(self, data):
model_type = self.model_type
slug = self.slug
model_qs = ContentType.objects.filter(model=model_type)
if not model_qs.exists() or model_qs.count() != 1:
raise ValidationError("This is not a valid content type")
SomeModel = model_qs.first().model_class()
obj_qs = SomeModel.objects.filter(slug=self.slug)
if not obj_qs.exists() or obj_qs.count() != 1:
raise ValidationError("This is not a slug for this content type")
######################### ######################### #########################
How do I need to make query here to check if the user already liked the Event or not?
I tried the following way, but it is not working.
user_act = Thumbsup.objects.filter(user=self.user, content_type=ContentType.objects.get_for_model(model_type))
if user_act.exists():
raise ValidationError("You have already liked the event")
return data
def create(self, validated_data):
content = validated_data.get("content")
if user:
main_user = user
else:
main_user = User.objects.all().first()
model_type = self.model_type
slug = self.slug
parent_obj = self.parent_obj
thumbsup = Thumbsup.objects.create_by_model_type(
model_type, slug, content, main_user,
parent_obj=parent_obj,
)
return thumbsup
return ThumbsUpCreateSerializer
Traceback:
File "E:\GIT\blog\backend\venv\lib\site-packages\django\core\handlers\exception.py" in inner
34. response = get_response(request)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\views\generic\base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in dispatch
497. response = self.handle_exception(exc)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in handle_exception
457. self.raise_uncaught_exception(exc)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in raise_uncaught_exception
468. raise exc
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in dispatch
494. response = handler(request, *args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\generics.py" in post
190. return self.create(request, *args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\mixins.py" in create
18. serializer.is_valid(raise_exception=True)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\serializers.py" in is_valid
235. self._validated_data = self.run_validation(self.initial_data)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\serializers.py" in run_validation
433. value = self.validate(value)
File "E:\GIT\test-heroku4\thumbsup\api\serializers.py" in validate
124. user_act = Thumbsup.objects.filter(user=self.user, content_type=ContentType.objects.get_for_model(model_type))
File "E:\GIT\blog\backend\venv\lib\site-packages\django\contrib\contenttypes\models.py" in get_for_model
40. opts = self._get_opts(model, for_concrete_model)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\contrib\contenttypes\models.py" in _get_opts
27. model = model._meta.concrete_model
Exception Type: AttributeError at /api/event/likes/create/
Exception Value: 'str' object has no attribute '_meta'
I checked the model instance before saving in model manager like below and it is working fine. I do not know whether this is the correct way to do the task or not (I'm very new to django. Suggestions are most welcome)
def create_by_model_type(self, model_type, slug, content, user, parent_obj=None):
model_qs = ContentType.objects.filter(model=model_type)
if model_qs.exists():
some_model = model_qs.first().model_class()
obj_qs = some_model.objects.filter(slug=slug)
if obj_qs.exists() and obj_qs.count() == 1:
instance = self.model()
instance.content = content
instance.user = user
instance.content_type = model_qs.first()
instance.object_id = obj_qs.first().id
if parent_obj:
instance.parent = parent_obj
#### Here I have checked for existence before saving the instance ####
if Thumbsup.objects.filter(object_id=instance.object_id, user=instance.user).exists():
raise ValidationError({'already_liked': 'You have already liked the item'})
instance.save()
return instance
return None

Resources