1

I am trying to construct a queryset dynamically using model method but in doing so I am receiving this error in django rest framework v2.4.5 and django 1.7.8:

Cannot resolve keyword 'review_count' into field. Choices are: description, id, name, review

I'm unable to display the queryset created by the construct_queryset method in my viewset, although it works fine in the django admin. I believe it has something to do with the way that django rest framework is instantiating the models. I am not entirely sure what might be causing this issue, any help would be appreciated, thank you.

I upgraded to django 1.8 but it's not supported by django rest framework v2.4.5 and I cannot upgrade to v3 at this time unfortunately.

models.py:

class Widget (models.Model):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=255)

class Review (models.Model):
    name = models.CharField(max_length=255)
    rating = models.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(5)]
    )
    widget = models.ForeignKey(Widget)

class WidgetQS(models.Model):
    """ A model used for constructing a dynamic queryset """
    ORDER_CHOICES = (
        ('annotate_review', 'order by review count'),
        ...
    )
    order_by_field = models.CharField(max_length=255, choices=ORDER_CHOICES)

    def construct_queryset(self, user=None):
        queryset = Widget.objects.all()

        if self.order_by_field == 'annotate_review':
            result_qs = queryset.annotate(
                review_count=Count('review')
            ).order_by('-review_count') 

        return result_qs

serializers.py:

class WidgetSerializer (serializers.HyperlinkedModelSerializer):
    objects = serializers.SerializerMethodField('get_objects')

    def get_objects(self, obj):
        request = self.context.get('request', None)
        if request:
            try:
                user = request.user
            except:
                user = None

        qs = obj.construct_queryset(user=user)
        if qs:
            return qs.values_list('id', flat=True)
        return []

views.py

class WidgetViewSet (ModelViewSet):
    serializer_class = WidgetQSSerializer
    queryset = WidgetQS.objects.all()

Stack Trace

Environment:


Request Method: GET
Request URL: http://localhost:8080/api/widgetqs

Django Version: 1.7.8
Python Version: 2.7.6
Installed Applications:
(u'grappelli',
 u'django.contrib.admin',
 u'django.contrib.auth',
 u'django.contrib.contenttypes',
 u'django.contrib.sessions',
 u'django.contrib.messages',
 u'django.contrib.staticfiles',
 u'django.contrib.humanize',
 u'corsheaders',
 u'rest_framework',
 u'social.apps.django_app.default',
 u'widget',
 u'debug_toolbar')
Installed Middleware:
(u'django.contrib.sessions.middleware.SessionMiddleware',
 u'django.middleware.common.CommonMiddleware',
 u'django.middleware.csrf.CsrfViewMiddleware',
 u'django.contrib.auth.middleware.AuthenticationMiddleware',
 u'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 u'django.contrib.messages.middleware.MessageMiddleware',
 u'django.middleware.clickjacking.XFrameOptionsMiddleware',
 u'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
 u'bugsnag.django.middleware.BugsnagMiddleware',
 u'debug_toolbar.middleware.DebugToolbarMiddleware')


Traceback:
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  57.         return view_func(*args, **kwargs)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
  79.             return self.dispatch(request, *args, **kwargs)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  403.             response = self.handle_exception(exc)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  400.             response = handler(request, *args, **kwargs)
File "/Users/nabil/Documents/projects/widget_project/widget_project/timestamp/mixins.py" in list
  108.             return Response(serializer.data)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  576.                 self._data = self.to_native(obj)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/serializers.py" in to_native
  355.             value = field.field_to_native(obj, field_name)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/serializers.py" in field_to_native
  414.             return [self.to_native(item) for item in value.all()]
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/serializers.py" in to_native
  355.             value = field.field_to_native(obj, field_name)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/fields.py" in field_to_native
  1043.         return self.to_native(value)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/rest_framework/fields.py" in to_native
  225.             return [self.to_native(item) for item in value]
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/query.py" in __iter__
  141.         self._fetch_all()
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/query.py" in _fetch_all
  966.             self._result_cache = list(self.iterator())
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/query.py" in iterator
  1202.             for row in self.query.get_compiler(self.db).results_iter():
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in results_iter
  701.         for rows in self.execute_sql(MULTI):
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  776.             sql, params = self.as_sql()
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in as_sql
  102.         ordering, o_params, ordering_group_by = self.get_ordering()
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in get_ordering
  430.                         self.query.get_meta(), default_order=asc):
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in find_ordering_name
  466.         field, targets, alias, joins, path, opts = self._setup_joins(pieces, opts, alias)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in _setup_joins
  499.             pieces, opts, alias)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/query.py" in setup_joins
  1463.             names, opts, allow_many, fail_on_missing=True)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/query.py" in names_to_path
  1427.             self.raise_field_error(opts, name)
File "/Users/nabil/.virtualenvs/widget_project/lib/python2.7/site-packages/django/db/models/sql/query.py" in raise_field_error
  1433.                          "Choices are: %s" % (name, ", ".join(available)))

Exception Type: FieldError at /api/widgetqs
Exception Value: Cannot resolve keyword 'review_count' into field. Choices are: description, id, name, review
njamaleddine
  • 162
  • 2
  • 13
  • EDIT: It's worth noting that my ultimate solution was to use queryset.extra() instead of annotate. There seems to be some sort of bug with django rest framework v2.4.5 that raises the error and doesn't fetch the annotate fields during serialization. That is my thought at least. I'll have to further investigate this. – njamaleddine Jul 07 '15 at 19:47
  • try this link: working very fine: https://stackoverflow.com/questions/31920853/aggregate-and-other-annotated-fields-in-django-rest-framework-serializers – Pramod Singh Jul 14 '17 at 02:12

1 Answers1

1

As you can see in your function :

def construct_queryset(self, user=None):
        queryset = Widget.objects.all()

        if self.order_by_field == 'annotate_review':
            result_qs = queryset.annotate(
                review_count=Count('review')
            ).order_by('-review_count') 

        return result_qs

Your queryset is

Widget.objects.all()

and you are trying to annotate a field which has no relation with your Review model. If you want this to work, you have to add a foreignkey to your model Review for Model Widget like this :

class Widget (models.Model):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=255)

class Review (models.Model):
    widget = models.ForeignKey(Widget)
    name = models.CharField(max_length=255)
    rating = models.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(5)]
    )
Ajay Gupta
  • 1,285
  • 8
  • 22
  • Apologies I copied in my model wrong, see my edit above, it is still receiving that error. Thank you – njamaleddine Jul 07 '15 at 16:25
  • Thank you, please see the stack trace above – njamaleddine Jul 07 '15 at 16:32
  • what is your error again ?? "Cannot resolve keyword 'widget_count' into field. Choices are: description, id, name, review" or the one in Traceback? – Ajay Gupta Jul 07 '15 at 16:41
  • review_count. If I only return the queryset in `construct_queryset` I get no errors. But when i perform queryset.annotate, it returns the traceback ex: if I just do `return queryset` it works fine – njamaleddine Jul 07 '15 at 16:42
  • can you once try Widget.objects.annotate(review_count=Count('review')).order_by('-review_count') , and see if helps! – Ajay Gupta Jul 07 '15 at 16:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/82628/discussion-between-ajay-gupta-and-njamaleddine). – Ajay Gupta Jul 07 '15 at 16:54