Django Rest Framework writable nested serializer raises AttributeError - python

I'm working on a Django based shipment management application. We have integrated the Django Rest Framework and exposed few end points.
Now the django app called "port_manager" has following models...
models.py
from location.models import CountryList, DistrictList
class PortList(models.Model):
name = models.CharField(max_length=45)
countryList_id = models.ForeignKey(CountryList, models.SET_NULL, blank=True, null=True, verbose_name='related country')
iso_code = models.CharField(max_length=10)
short_code = models.CharField(max_length=10, null=True, blank=True)
status = models.BooleanField(default=True)
def __str__(self):
return self.name
class PortDetail(models.Model):
port = models.OneToOneField(PortList, models.CASCADE, verbose_name='related port', primary_key=True)
phone = models.CharField(max_length=15)
district_list_id = models.ForeignKey(DistrictList, models.SET_NULL, blank=True, null=True,
verbose_name='related district')
email = models.EmailField()
fax = models.CharField(max_length=100, null=True, blank=True)
address = models.TextField()
map_location = models.CharField(max_length=45, null=True, blank=True)
other_information = models.TextField(null=True, blank=True)
current_pricing = models.IntegerField(null=True, blank=True)
def __str__(self):
return self.port.name+' Details'
serializers.py
from rest_framework import serializers
from port_manager.models import PortList, PortDetail
from location.models import CountryList, DistrictList
class PortListSerializer(serializers.ModelSerializer):
countryList_id = serializers.PrimaryKeyRelatedField(queryset=CountryList.objects.all(), write_only=True)
class Meta:
model = PortList
fields = ('name', 'countryList_id', 'iso_code')
class PortDetailSerializer(serializers.ModelSerializer):
district_list_id = serializers.PrimaryKeyRelatedField(queryset=DistrictList.objects.all(),)
class Meta:
model = PortDetail
fields = ('port', 'phone', 'district_list_id', 'email', 'fax', 'address',
'map_location', 'other_information', 'current_pricing')
class PortSerializer(serializers.ModelSerializer):
port = PortListSerializer()
district_list_id = serializers.PrimaryKeyRelatedField(queryset=DistrictList.objects.all(), write_only=True)
class Meta:
model = PortDetail
def create(self, validated_data):
port_data = validated_data.pop('port')
port = PortList.objects.create(**port_data)
PortDetail.objects.create(port=port, **validated_data)
return PortDetail
Now when I POST to the end point using CURL it inserts into both of the tables in the database but raise error(400)
curl sample POST request
curl -H "Authorization: Token afab77f7c9320d396442eb1aef9a3bd5de54c3ce" -X POST -d '{"port":{"name":"Singapore", "countryList_id":"3", "iso_code":"SIN", "short_code":"898"},"district_list_id":"9", "email":"asd#aassd.com", "fax":"23423432", "other_information":"adasd sdas", "address":"asdas asd", "phone":"123412312"}' http://example.org/api/v1/portcombined/
Full stack from Django error log:
Internal Server Error: /api/v1/portcombined/
Traceback (most recent call last):
File "/usr/local/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/usr/local/lib/python3.5/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/rest_framework/decorators.py", line 53, in handler
return func(*args, **kwargs)
File "/home/gpsl/sites/container/src/port_manager/views.py", line 143, in port_merged
return JSONResponse(serializer.data, status=201)
File "/usr/local/lib/python3.5/site-packages/rest_framework/serializers.py", line 503, in data
ret = super(Serializer, self).data
File "/usr/local/lib/python3.5/site-packages/rest_framework/serializers.py", line 239, in data
self._data = self.to_representation(self.instance)
File "/usr/local/lib/python3.5/site-packages/rest_framework/serializers.py", line 472, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/usr/local/lib/python3.5/site-packages/rest_framework/serializers.py", line 463, in to_representation
attribute = field.get_attribute(instance)
File "/usr/local/lib/python3.5/site-packages/rest_framework/relations.py", line 157, in get_attribute
return get_attribute(instance, self.source_attrs)
File "/usr/local/lib/python3.5/site-packages/rest_framework/fields.py", line 80, in get_attribute
instance = getattr(instance, attr)
AttributeError: 'ForwardManyToOneDescriptor' object has no attribute 'countryList_id'
Thanks to you all for taking your time and go through all these.

The problem is that context is not passed to nested serializers. Your PortSerializer class should have an __init__ method and there you should explicitly pass context to your nested serializer. See the example below:
class PortSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super(PortSerializer, self).__init__(*args, **kwargs)
self.fields['port'] = PortListSerializer(context=self.context)

I think, you should not use countryList_id modelfield. Because, by default Django return the id of the object with object_id.
If you rename your model with countryList and pass countryList from the API, the Django will surely get the CountryList object.

Related

Atrribute Error in Django web application

I have been trying this for some days now with no solution.I am getting this weird error after which I have made several trials all of which hasn't solved my issue, I would be glad to receive a solution.
ERROR LOGS
Traceback (most recent call last):
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\views\generic\base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\views\generic\base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\views\generic\list.py", line 142, in get
self.object_list = self.get_queryset()
File "C:\Users\Habib\Documents\django\django-new\student-management-system\student_management_app\StaffViews.py", line 364, in get_queryset
queryset = self.request.user.quizzes \
File "C:\Users\Habib\Documents\django\django-new\student-management-system\venv\lib\site-packages\django\utils\functional.py", line 225, in inner
return func(self._wrapped, *args)
Exception Type: AttributeError at /staff_quiz_home/
Exception Value: 'CustomUser' object has no attribute 'quizzes'
MODELS.PY
class CustomUser(AbstractUser):
user_type_data = ((1, "HOD"), (2, "Staff"), (3, "Student"))
user_type = models.CharField(default=1, choices=user_type_data, max_length=10)
class Quiz(models.Model):
owner = models.ForeignKey(Staffs, on_delete=models.CASCADE, related_name='quizzes')
name = models.CharField(max_length=255)
subject = models.ForeignKey(Subjects, on_delete=models.CASCADE, related_name='quizzes')
class student(models.Model):
name = models.CharField(max_length=255)
admin = models.OneToOneField(CustomUser, on_delete = models.CASCADE)
gender = models.CharField(max_length=50)
quizzes = models.ManyToManyField(Quiz, through='TakenQuiz')
class Staffs(models.Model):
name = models.CharField(max_length=255)
admin = models.OneToOneField(CustomUser, on_delete = models.CASCADE)
address = models.TextField()
class Subjects(models.Model):
name = models.CharField(max_length=255)
staff_id = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
VIEWS.PY
class QuizListView(ListView):
model = Quiz
ordering = ('name', )
context_object_name = 'quizzes'
template_name = "staff_template/quiz_home_page.html"
def get_queryset(self):
queryset = self.request.user.quizzes \
.select_related('subject') \
.annotate(questions_count=Count('questions', distinct=True)) \
.annotate(taken_count=Count('taken_quizzes', distinct=True))
return queryset
Thanks in advance, if you need anymore info please do let me know.
Your Quiz object is related to Staffs and not CustomUser so you should access it through
self.request.user.staffs.quizess
Other than that it is clear that you cannot do Query on a set so you should do something in a line of
Quiz.object.filter(owner__admin=request.user).
...

Django rest framework's StringRelatedField is throwing KeyError

I have the following model classes.
class Categories(models.Model):
id = models.UUIDField(primary_key=True, auto_created=True, default=uuid.uuid4, unique=True)
business = models.ForeignKey(Business, related_name='category_business', on_delete=models.CASCADE)
name = models.CharField(max_length=128)
class Meta:
unique_together = ('business', 'name')
class Menu(models.Model):
id = models.UUIDField(primary_key=True, auto_created=True, default=uuid.uuid4, unique=True)
business = models.ForeignKey(Business, related_name='menu_business', on_delete=models.CASCADE)
name = models.CharField(max_length=128)
description = models.CharField(max_length=128)
category = models.ForeignKey(Categories, related_name='menus', on_delete=models.CASCADE)
price = models.IntegerField()
class Meta:
unique_together = ('business', 'name', 'category')
def __str__(self):
return '%s %s %s' % (self.name, self.price, self.description)
and I have imported these classes as following as they are located in a separate package
Categories = apps.get_model('business', 'Categories')
Menu = apps.get_model('business', 'Menu')
and this is my serializer class
class GetCategoriesSerializer(serializers.ModelSerializer):
menus = serializers.StringRelatedField(many=True)
class Meta:
model = Categories
fields = ('name', 'menus')
and views is
class GetCategories(generics.ListAPIView):
"""
Returns a list of businesses to the user. It'd read only and no authentication is needed
"""
permission_classes = [ReadOnly]
queryset = Categories.objects.values()
serializer_class = GetCategoriesSerializer
and url has the following
path('customer/<str:pk>/categories', GetCategories.as_view()),
I am getting the following error
Traceback (most recent call last):
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
raise exc
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/generics.py", line 199, in get
return self.list(request, *args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/mixins.py", line 48, in list
return Response(serializer.data)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 760, in data
ret = super().data
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 678, in to_representation
self.child.to_representation(item) for item in iterable
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 678, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 516, in to_representation
attribute = field.get_attribute(instance)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/relations.py", line 529, in get_attribute
relationship = get_attribute(instance, self.source_attrs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/fields.py", line 92, in get_attribute
instance = instance[attr]
Exception Type: KeyError at /customer/85f44d20-f936-4940-8e15-01393e42c4a8/categories
Exception Value: 'menus'
I looked into the DRF example and this seems to be a simple thing to achieve.
https://www.django-rest-framework.org/api-guide/relations/#api-reference
But I am kind of stuck at this point. Am I doing anything wrong? Thanks in advance for any help.
You should've used the QuerySet instead of ValueQuerySet. That is use queryset = Categories.objects.all() instead of queryset = Categories.objects.values()
So change the queryset attribute of the view as,
class GetCategories(generics.ListAPIView):
permission_classes = [ReadOnly]
queryset = Categories.objects.all()
serializer_class = GetCategoriesSerializer

Django REST Framework: AttributeError: 'DeferredAttribute' object has no attribute 'isoformat'

This is my first time using Django REST FRAMEWORK, I'm facing an issue with a registration api, on the first try the api worked properly, but on the following tries it started throwing this error
AttributeError: 'DeferredAttribute' object has no attribute 'isoformat'
first here is my code:
serializers.py:
class UserSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = User.objects.create(**validated_data)
user.set_password(validated_data['password'])
user.save()
# return dict(status=True, code=1)
return User
class Meta:
model = User
fields = ['phone', 'email', 'first_name', 'last_name', 'birth_date', 'gender', 'user_type', 'password',
'username']
extra_kwargs = {
"password": {"write_only": True}
}
apis.py:
class RegisterApi(CreateAPIView):
model = get_user_model()
permission_classes = [permissions.AllowAny]
serializer_class = UserSerializer
models.py:
class User(AbstractUser):
notification_token = models.CharField(max_length=255, unique=True, blank=True, null=True)
phone = models.CharField(
_("Phone Number"),
max_length=50,
validators=[phone_validator],
unique=True,
)
is_active = models.BooleanField(
_('active'),
default=False,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
photo = models.ImageField(
_('Profile Picture'),
upload_to='profile/',
help_text=_(
"the user's profile picture."
),
blank=True,
null=True
)
address = models.CharField(_("Address"), max_length=255)
lives_in = models.ForeignKey('City', on_delete=do_nothing, null=True, blank=True)
user_type = models.CharField(
_("Type"),
max_length=3,
choices=USER_TYPES,
help_text=_("The user's type can be one of the available choices, "
"refer to the Model class for the detailed list."),
)
birth_date = models.DateField(_('Birth Date'), blank=True, null=True)
gender = models.CharField(choices=GENDERS, max_length=1, default='M')
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["first_name", "last_name", 'user_type', 'phone', 'email']
#property
def get_age(self) -> int:
today = date.today()
dob = self.birth_date
before_dob = (today.month, today.day) < (dob.month, dob.day)
return today.year - self.birth_date.year - before_dob
#property
def confirmed_phone(self) -> bool:
return False
#property
def confirmed_email(self) -> bool:
return False
def __str__(self):
return self.phone
now when i post
i get this error:
Internal Server Error: /api/register/
Traceback (most recent call last):
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\django\views\generic\base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\views.py", line 476, in raise_uncaught_exception
raise exc
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\generics.py", line 190, in post
return self.create(request, *args, **kwargs)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\mixins.py", line 20, in create
headers = self.get_success_headers(serializer.data)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\serializers.py", line 562, in data
ret = super().data
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\serializers.py", line 529, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "C:\Users\Simou\Desktop\Work\IT-GDS\Resto\web\restaurant\venv\lib\site-packages\rest_framework\fields.py", line 1327, in to_representation
return value.isoformat()
AttributeError: 'DeferredAttribute' object has no attribute 'isoformat'
Knowing that the users are being registered in the database, but the response is throwing this error.
any help is appreciated.
You should return user instance from create() method, not User class:
class UserSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = User.objects.create(**validated_data)
user.set_password(validated_data['password'])
user.save()
# return dict(status=True, code=1)
return user # instead of User

Django "TypeError: '...' object is not iterable"

I need multiple values to be in the courses' contacts, for example, phone, Facebook, etc.
I'm overriding create a method to make writable nested fields. Everything works fine with "branches". I'm confused because I can't get why Contact is not iterable.
Models.py:
class Branch(models.Model):
latitude = models.CharField(max_length=50)
longitude = models.CharField(max_length=50)
address = models.CharField(max_length=100)
class Meta:
ordering = ['latitude']
def __str__(self):
return self.address
class Contact(models.Model):
type = models.IntegerField(choices=TYPE, default=1)
value = models.CharField(max_length=100, null=False)
class Meta:
ordering = ['type']
def __str__(self):
return "{} {}".format(self.type, self.value)
class Course(models.Model):
...
branches = models.ForeignKey(Branch, on_delete=models.CASCADE, null=False, default=True)
contacts = models.ForeignKey(Contact, on_delete=models.CASCADE, null=False, default=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
Serializers.py:
class CourseSerializer(serializers.ModelSerializer):
...
branches = BranchSerializer(many=True)
contacts = ContactSerializer(many=True)
class Meta:
model = Course
fields = ['name', 'description', 'category', 'logo', 'contacts', 'branches']
def create(self, validated_data):
branches_data = validated_data.pop('branches')
contacts_data = validated_data.pop('contacts')
course = Course.objects.create(**validated_data)
for branches in branches_data:
branch = Branch.objects.create(**branches)
course.branches = branch
for contacts in contacts_data:
contact = Contact.objects.create(**contacts)
course.contacts = contact
return course
UPD: Traceback:
File "/courseapp_task/venv/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/courseapp_task/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "/courseapp_task/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/viewsets.py" in view
114. return self.dispatch(request, *args, **kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
505. response = self.handle_exception(exc)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
465. self.raise_uncaught_exception(exc)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in raise_uncaught_exception
476. raise exc
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
502. response = handler(request, *args, **kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/mixins.py" in create
20. headers = self.get_success_headers(serializer.data)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in data
559. ret = super().data
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in data
261. self._data = self.to_representation(self.instance)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in to_representation
526. ret[field.field_name] = field.to_representation(attribute)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in to_representation
675. self.child.to_representation(item) for item in iterable
The problem is not in your nested serializers. The problem is in your models themselves.
A ForeignKey is a many to one relationship. The way you have defined things, a Course can only have one branch and one contact. Calling the fields "branches" and "contacts" doesn't change that, and neither does setting "many=True" in the serializers.
You need to change the models so that the ForeignKeys are on Branch and Contact themselves, pointing at Course. The serializer would then use the related names.
Note, you shouldn't need to define create; everything there should just work.

DjangoFilterBackend not working with my models (manytomany)

I have a Django REST project in which I used the DjangoFilterBackend from django-rest-framework-filtersgithub link.
This backend works well for some of my models which has ForeignKey & ManyToMany relations, however, it just doesn't work for some other models and always gives me an AttributeError: 'NoneType' object has no attribute 'verbose_name'.
my model:
from django.db import models
from authuser.models import AbstractUser, BaseUserManager
from corporation.models import Corporation
class Organization(AbstractUser):
company = models.ForeignKey(Corporation, verbose_name='company',
related_name='organizations',
null=True, on_delete=models.SET_NULL)
contact_name = models.CharField(max_length=50, verbose_name='contact_name', default='')
contact_phone = models.CharField(max_length=50, null=True, verbose_name='contact_phone')
contact_email = models.EmailField(max_length=50, verbose_name='contact_email', default='')
about_us = models.TextField(null=True, verbose_name='about_us')
info_completed = models.BooleanField(default=False, verbose_name='info_completed')
objects = BaseUserManager()
class Meta:
ordering = ('date_joined',)
my views:
class OrganizationDetailView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = OrganizationSerializer
queryset = Organization.objects.all()
class OrganizationListCreateView(generics.ListCreateAPIView):
queryset = Organization.objects.all()
permission_classes = ()
def get_serializer_class(self):
if self.request.method == "POST":
return CreateOrganizationSerializer
return OrganizationSerializer
filter_backends = (
rest_backends.DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter,
)
filter_fields = (
'contact_name',
)
filter_class = OrganizationFilter
search_fields = (
# 'company',
'contact_name',
'contact_email', 'contact_phone',
'description',
)
ordering = ('date_joined')
my filterset:
class OrganizationFilter(filters.FilterSet):
company = filters.RelatedFilter(CorporationFilter, name='company')
description = filters.AllLookupsFilter(name='description')
contact_name = filters.AllLookupsFilter(name='contact_name')
contact_phone = filters.AllLookupsFilter(name='contact_phone')
contact_email = filters.AllLookupsFilter(name='contact_email')
class Meta:
model = Organization
fields = (
'company',
'description', 'contact_name', 'contact_phone',
'contact_email',
)
my serializer:
class OrganizationSerializer(serializers.ModelSerializer):
company = serializers.PrimaryKeyRelatedField(queryset=Corporation.objects.all())
class Meta:
model = Organization
fields = ('id', 'company',
'contact_name', 'contact_email',
'contact_phone', 'info_completed')
The CRUD operations are fine. It just gives me the attribute error when listing organizations:
Creating test database for alias 'default'...
E.........
======================================================================
ERROR: test_list_organizations (organization.tests.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "F:\landi-django\organization\tests.py", line 73, in test_list_organizati
ons
response = client.get('/organizations?contact_name=Tingtao')
File "F:\landi-django\env\lib\site-packages\rest_framework\test.py", line 160,
in get
response = super(APIClient, self).get(path, data=data, **extra)
File "F:\landi-django\env\lib\site-packages\rest_framework\test.py", line 86,
in get
return self.generic('GET', path, **r)
File "F:\landi-django\env\lib\site-packages\rest_framework\compat.py", line 18
9, in generic
return self.request(**r)
File "F:\landi-django\env\lib\site-packages\rest_framework\test.py", line 157,
in request
return super(APIClient, self).request(**kwargs)
File "F:\landi-django\env\lib\site-packages\rest_framework\test.py", line 109,
in request
request = super(APIRequestFactory, self).request(**kwargs)
File "F:\landi-django\env\lib\site-packages\django\test\client.py", line 440,
in request
six.reraise(*exc_info)
File "F:\landi-django\env\lib\site-packages\django\core\handlers\base.py", lin
e 111, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "F:\landi-django\env\lib\site-packages\django\views\decorators\csrf.py",
line 57, in wrapped_view
return view_func(*args, **kwargs)
File "F:\landi-django\env\lib\site-packages\django\views\generic\base.py", lin
e 69, in view
return self.dispatch(request, *args, **kwargs)
File "F:\landi-django\env\lib\site-packages\rest_framework\views.py", line 407
, in dispatch
response = self.handle_exception(exc)
File "F:\landi-django\env\lib\site-packages\rest_framework\views.py", line 404
, in dispatch
response = handler(request, *args, **kwargs)
File "F:\landi-django\env\lib\site-packages\rest_framework\generics.py", line
311, in get
return self.list(request, *args, **kwargs)
File "F:\landi-django\env\lib\site-packages\rest_framework\mixins.py", line 40
, in list
instance = self.filter_queryset(self.get_queryset())
File "F:\landi-django\env\lib\site-packages\rest_framework\generics.py", line
144, in filter_queryset
queryset = backend().filter_queryset(self.request, queryset, self)
File "F:\landi-django\env\lib\site-packages\rest_framework_filters\backends.py
", line 45, in filter_queryset
_filter = filter_class(request.QUERY_PARAMS, queryset=queryset)
File "F:\landi-django\env\lib\site-packages\rest_framework_filters\filterset.p
y", line 61, in __init__
f = self.filter_for_field(field, filter_.name)
File "F:\landi-django\env\lib\site-packages\django_filters\filterset.py", line
400, in filter_for_field
'label': capfirst(f.verbose_name),
AttributeError: 'NoneType' object has no attribute 'verbose_name'
----------------------------------------------------------------------
I also tried commenting line 400 in django_filters\filterset.py, but it gives me more errors.
Many thanks for your help!
On your OrganizationFilter, you are defining a description field that can be used to filter down to Organization objects. The description field does not exist on the Organization model though, so django-filter is not able to filter the queryset based on that field. You do appear to have an about_us field, which I'm guessing is what you meant to use.
You can fix this issue by either renaming the field on the OrganizationFilter to about_us, or setting the name on the description field to be about_us, so django-filter uses that field instead.
class OrganizationFilter(filters.FilterSet):
company = filters.RelatedFilter(CorporationFilter, name='company')
about_us = filters.AllLookupsFilter(name='about_us')
contact_name = filters.AllLookupsFilter(name='contact_name')
contact_phone = filters.AllLookupsFilter(name='contact_phone')
contact_email = filters.AllLookupsFilter(name='contact_email')
class Meta:
model = Organization
fields = (
'company',
'description', 'contact_name', 'contact_phone',
'contact_email',
)
Either of these changes should make it work without throwing an error.

Categories

Resources