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

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

Related

AttributeError at admin: 'NoneType' object has no attribute 'startswith'

Below is my error:
AttributeError at /admin/r/31/3/
'NoneType' object has no attribute 'startswith'
Request Method: GET
Request URL: http://127.0.0.1:8000/admin/r/31/3/
Django Version: 3.2.13
Exception Type: AttributeError
Exception Value:
'NoneType' object has no attribute 'startswith'
Exception Location: C:\github\project\venv\lib\site-packages\django\contrib\contenttypes\views.py, line 41, in shortcut
Python Executable: C:\github\project\venv\Scripts\python.exe
Python Version: 3.7.1
This occurs when I'm trying to access certain type of model via admin, since I cannot access it through the tag related to get_absolute_url function of the model. The template appears, but never let me access the get_absolute_url.
The thing is, there is another model in another app which is almost identical in views.py, urls.py and models.py but only difference is 'permission_required' decorator which I can't sure if it's outdated.
views.py of error model.
from django.urls import reverse_lazy
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import login_required, permission_required
from .models import *
def landing(request):
return render(
request,
'instructor/landing.html'
)
def paymentrequired(request):
return render(
request,
'instructor/paymentrequired.html'
)
def lecture_in_category(request, category_slug=None):
current_category = get_object_or_404(Category, slug=category_slug)
categories = Category.objects.all()
lectures = Lecture.objects.filter(category=current_category)
return render(request, 'instructor/lecture_list.html',
{'current_category': current_category, 'categories': categories, 'lectures': lectures})
class LectureDetail(DetailView):
model = Lecture
def lecture_detail(request, id):
lecture = get_object_or_404(Lecture, id=id)
return render(request, 'instructor/lecture_detail.html', {'lecture':lecture})
# Create your views here.
models.py of the error page
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
import os
class Category(models.Model):
name = models.CharField(max_length=200, db_index=True)
meta_description = models.TextField(blank=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True, allow_unicode=True)
class Meta:
ordering = ['name']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('instructor:lecture_in_category', args=[self.slug])
class Lecture(models.Model):
title = models.CharField(max_length=40)
description = models.CharField(max_length=200, blank=True)
video_key = models.CharField(max_length=20, blank=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True, allow_unicode=True)
video_upload = models.FileField(upload_to='instructor/files/%Y/%m/%d', blank=True)
head_image = models.ImageField(upload_to='instructor/images/%Y/%m/%d', blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
available_display = models.BooleanField('Display', default=True)
author = models.CharField(max_length=40)
category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
class Meta:
ordering = ['-created_at']
index_together = [['id', 'slug']]
def __str__(self):
return self.title
def get_absolute_url(self):
reverse('instructor:lecture_detail', args=[self.id, self.slug])
# Create your models here.
urls.py of the error page
from django.urls import path
from . import views
from .views import *
app_name = 'instructor'
urlpatterns = [
path('', landing, name='landing'),
path('<slug:category_slug>/', lecture_in_category, name='lecture_list_category'),
path('<int:id>/<lecture_slug>/', LectureDetail.lecture_detail, name="lecture_detail"),
path('payment_required/', paymentrequired, name="paymentrequired"),
]
this is my database setting
DATABASES = {
'default': {
'ENGINE': os.environ.get("SQL_ENGINE", 'django.db.backends.sqlite3'),
'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')),
'USER': os.environ.get('SQL_USER', 'user'),
'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
'HOST': os.environ.get('SQL_HOST', 'localhost'),
'PORT': os.environ.get("SQL_PORT", '5432'),
}
}
This is the traceback.
Traceback (most recent call last):
File "C:\github\rhizomeedu\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\contrib\admin\sites.py", line 250, in wrapper
return self.admin_view(view, cacheable)(*args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\views\decorators\cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\contrib\admin\sites.py", line 232, in inner
return view(request, *args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\contrib\contenttypes\views.py", line 41, in shortcut
if absurl.startswith(('http://', 'https://', '//')):
AttributeError: 'NoneType' object has no attribute 'startswith'
With that model, the error doesn't appear so I once deleted the decorator but the result was same.
So I assume it's about settings.py ..?
Help me.

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

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

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

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

Django-3.1/DRF/React: Unable to save nested images (linked through GenericRelation)

I am building a Django+DRF/React app (simple blog app) and i am facing difficulties saving nested images
Model Structure
Model:
Post
Children:
details: ContentType Model ( DRF: save is successfull )
images: ContentType Model ( DRF : save is not successfull )
Process
Send images from <input type="file" multiple />
Process data through FormData
Catch request.data and process it
class PostFormView(generics.RetrieveUpdateDestroyAPIView):
queryset = Post._objects.is_active()
serializer_class = PostModelSerializer
permission_classes = (IsOwnerOr401,)
parser_classes = (parsers.MultiPartParser,parsers.JSONParser,
parsers.FormParser, parsers.FileUploadParser)
lookup_field = 'slug'
lookup_url_kwarg = 'slug'
def get_queryset(self):
return super().get_queryset().annotate(**sharedAnnotations(request=self.request))
def update(self, request, *args, **kwargs):
data = request.data
_images = data.getlist('images')
images = []
for _ in _images:
if isinstance(_, dict):
images.append(images)
continue
images.append({'image': _, 'object_id': self.get_object().pk, 'content_type': self.get_object().get_content_type().pk})
data['images'] = images
print(data)
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
instance._prefetched_objects_cache = {}
return Response(serializer.data)
Save images (FAIL):
class MediaModelSerializer(ContentTypeModelSerializer):
# inherits object_id & content_type fields just to avoid writing them over and over alongside (create & update fns)
class Meta:
model = Media
fields='__all__'
class PostModelSerializer(WritableNestedModelSerializer):
is_active = serializers.BooleanField(default=True)
path = serializers.HyperlinkedIdentityField(
view_name="api:post-detail", lookup_field='slug')
images = MediaModelSerializer(many=True)
details = DetailModelSerializer(required=False, many=True)
# annotated fields
is_author = serializers.BooleanField(read_only=True, default=False)
class Meta:
model = Post
fields = '__all__'
read_only_fields = ['is_locked', 'slug', 'user', 'is_author']
def create(self, validated_data):
return super().create(validated_data)
def update(self, instance, validated_data):
return super().update(instance, validated_data)
The print(data) statement from PostFormView.update(self, request, *args, **kwargs) (after manipulation) returns this:
<QueryDict: {'id': ['8'], ..., 'images': [[{'image': <InMemoryUploadedFile: bmw_3.jpeg (image/jpeg)>, 'object_id': 8, 'content_type': 20}, {'image': <InMemoryUploadedFile: bmw_2.jpeg (image/jpeg)>, 'object_id': 8, 'content_type': 20}, {'image': <InMemoryUploadedFile: bmw_1.jpeg (image/jpeg)>, 'object_id': 8, 'content_type': 20}]]}>
Server returns 400_BAD_REQUEST because images were not passed to PostModelSerializer
{"images":["This field is required."]}
i've been facing this issue for 3 days and i can't wrap my head around the root cause.
Thank you for your help.
i have been looking all over the internet but i could not find any anwsers so i had to go this way
I have removed the processing part from PostFormView.update(...) and accessed the images directly in the create & update methods of the ModelSerializer. I'll figure out later on how to handle removing these images
Here's the code:
class PostModelSerializer(WritableNestedModelSerializer):
is_active = serializers.BooleanField(default=True)
path = serializers.HyperlinkedIdentityField(
view_name="api:post-detail", lookup_field='slug')
images = MediaModelSerializer(read_only=True, many=True)
details = DetailModelSerializer(required=False, many=True)
# annotated fields
is_author = serializers.BooleanField(read_only=True, default=False)
class Meta:
model = Post
fields = '__all__'
read_only_fields = ['is_locked', 'slug', 'user', 'is_author']
def create(self, validated_data):
instance = super().create(validated_data)
request = self.context.get('request', None)
if request:
try:
images = request.data.getlist('images')
for image in images:
self.instance.images.create(image=image)
except Exception as e:
pass
return instance
def update(self, instance, validated_data):
instance = super().update(instance, validated_data)
request = self.context.get('request', None)
if request:
try:
images = request.data.getlist('images')
for image in images:
self.instance.images.create(image=image)
except Exception as e:
pass
return instance
If anyone has faced this issue before and managed to resolve it, please post your answer below.
Thank you !

Resources