Reputation: 141
I am building a larger Django-based web app, but I have a blocking issue with an API view that should return some data.
I the application I have a model (mail.models.Message
) and a matching serializer and viewset.
For a reporting feature, I need to get filtered set of results and have therefoer created a seperate rest_framework.views.APIView for the purpose of the reporting. The model is located in one app and the reporting is in another app.
Here is the model:
class Message(models.Model):
class Meta:
ordering = ('-timestamp',)
get_latest_by = 'timestamp'
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
from_address = models.CharField("From", max_length=511, blank=True, default="", db_index=True)
from_domain = models.CharField(max_length=255, blank=True, default="", db_index=True)
to_address = models.CharField("To", max_length=511, blank=True, default="", db_index=True)
to_domain = models.CharField(max_length=255, blank=True, default="", db_index=True)
subject = models.TextField(blank=True, default="", db_index=True)
client_ip = models.GenericIPAddressField("Client IP", db_index=True, null=True)
mailscanner_hostname = models.CharField(max_length=255, db_index=True)
spam_score = models.DecimalField(db_index=True, default=0.00, max_digits=7, decimal_places=2)
mcp_score = models.DecimalField(db_index=True, default=0.00, max_digits=7, decimal_places=2)
timestamp = models.DateTimeField(db_index=True)
size = models.FloatField(default=0)
token = models.CharField(max_length=255, null=True)
mailq_id = models.TextField("Mailqueue identification", null=True)
whitelisted = models.BooleanField(db_index=True, default=False)
blacklisted = models.BooleanField(db_index=True, default=False)
is_spam = models.BooleanField(db_index=True, default=False)
is_mcp = models.BooleanField(db_index=True, default=False)
is_rbl_listed = models.BooleanField("Is RBL listed", db_index=True, default=False)
quarantined = models.BooleanField(db_index=True, default=False)
infected = models.BooleanField(db_index=True, default=False)
released = models.BooleanField(db_index=True, default=False)
def __str__(self):
return str(self.id) + "[" + str(self.from_address) + " to " + str(self.to_address) + "]"
And the matching serializer:
class MessageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Message
fields = (
'id',
'url',
'from_address',
'from_domain',
'to_address',
'to_domain',
'subject',
'client_ip',
'mailscanner_hostname',
'spam_score',
'timestamp',
'size',
'token',
'whitelisted',
'blacklisted',
'is_spam',
'is_rbl_listed',
'quarantined',
'infected'
)
The model has a lot of indexes on it to improve the performance search and filtering, but I have excluded these.
For the reporting, I have created this special view:
class MessageListApiView(ReportApiView):
serializer_class = MessageSerializer
queryset = Message.objects.all()
def get_queryset(self):
if self.request.method == 'POST':
filters = self.request.data
return MessageQuerySetFilter.filter(MessageQuerySetFilter, self.queryset, filters)
else:
return self.queryset
def post(self, request, format=None):
filters = request.data
qs = self.get_queryset()
serializer = MessageSerializer(qs, context={'request': request})
return Response(serializer.data, 200)
In get_queryset
, I use a special class and the only purpose of that class is to apply the appropriate filtering on the queryset and return it. Doing some testing, I have found the issue occurs when I have to return the Response
.
I get this traceback:
Internal Server Error: /api/reports/messages/
Traceback (most recent call last):
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
response = self.handle_exception(exc)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/views.py", line 454, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/views.py", line 491, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/kenneth/Code/mailware/src/reports/views.py", line 44, in post
return Response(serializer.data, 200)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/serializers.py", line 537, in data
ret = super(Serializer, self).data
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/serializers.py", line 262, in data
self._data = self.to_representation(self.instance)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/serializers.py", line 504, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/relations.py", line 376, in to_representation
url = self.get_url(value, self.view_name, request, format)
File "/Users/kenneth/Code/mailware/lib/python3.6/site-packages/rest_framework/relations.py", line 312, in get_url
lookup_value = getattr(obj, self.lookup_field)
AttributeError: 'QuerySet' object has no attribute 'pk'
[19/Jan/2018 20:05:24] "POST /api/reports/messages/ HTTP/1.1" 500 16389
The above APIView
class inherits a custom base class, which is what inherits the rest_framework.views.APIView
class. This class is called ReportApiView
and simply sets the paginator_class
and the permission_class
class ReportApiView(APIView):
permission_classes = (IsAuthenticated,)
pagination_class = PageNumberPaginationWithPageCount
In the MessageListApiView
post
method it seems to go wrong in the return
line, but I cannot find the reason why it is not working
Upvotes: 2
Views: 9373
Reputation: 1812
I faced the similar issue after adding many=True, finally by making the below change it worked.
class Meta:
extra_kwargs = {"id": {"validators": []}}
Upvotes: 0
Reputation: 2418
Are you using a nested serializer, and the parent serializer has a model which has unique_together constraint? See below on how to overriding the
get_unique_together_validators` method to disable unique together checks, because the instance is not passed into nested serializer, and hence fails the check
class FooSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
class Meta:
model = models.Foo
fields = '__all__'
list_serializer_class = FooListSerializer
def get_unique_together_validators(self):
"""Overriding method to disable unique together checks, because the instance is not passed into nested serializer, and hence fails the check"""
return []
Upvotes: 1
Reputation: 837
I had this error, for the ones coming here from Google, my problem was this one:
The model I wanted to serialize had a field containing unique=True
in it. The multiple data I sent to the Serializer (with many=True
) were not unique (already in db), and instead of having an error telling me this, the "'QuerySet' object has no attribute 'pk'"
was thrown which is really confusing. Anyway, after getting rid of the uniqueness, my code works.
Upvotes: 0
Reputation: 49
just you need to add many = true in serializer serializer = userSerializer.UserSeria(user,data=request.data,many=True)
Upvotes: 0
Reputation: 47374
You need to add many=True
to serializer queryset:
serializer = MessageSerializer(qs, many=True, context={'request': request})
Upvotes: 9