Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django annotate on prefetched filtered related model

I have a User model, each User can have many Post by this relateion:

class Post(models.Model):
    ...
    user = models.ForeignKey('User', related_name='posts')

, and each post have a like_count (integer field), i want to get users (along their posts) that has more that n posts which is liked more that m times, i do:

User.objects.prefetch_related(Prefetch('posts', queryset=Post.objects.filter(like_count__gte=m), to_attr='top_posts')).annotate(top_post_count=Count('top_posts')).filter(top_post_count__gte=n)

but, i get:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/query.py", line 912, in annotate
    clone.query.add_annotation(annotation, alias, is_summary=False)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/sql/query.py", line 971, in add_annotation
    summarize=is_summary)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/aggregates.py", line 19, in resolve_expression
    c = super(Aggregate, self).resolve_expression(query, allow_joins, reuse, summarize)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/expressions.py", line 513, in resolve_expression
    c.source_expressions[pos] = arg.resolve_expression(query, allow_joins, reuse, summarize, for_save)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/expressions.py", line 463, in resolve_expression
    return query.resolve_ref(self.name, allow_joins, reuse, summarize)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/sql/query.py", line 1462, in resolve_ref
    self.get_initial_alias(), reuse)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/sql/query.py", line 1402, in setup_joins
    names, opts, allow_many, fail_on_missing=True)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/sql/query.py", line 1327, in names_to_path
    "Choices are: %s" % (name, ", ".join(available)))
django.core.exceptions.FieldError: Cannot resolve keyword 'top_posts' into field. Choices are: ...
like image 870
Mohsen Avatar asked Sep 06 '16 17:09

Mohsen


1 Answers

The docs explain it's assigned to an attribute, named according to the to_attr parameter, on the QuerySet items.

I don't think that implies it's accessible as a model field to which a subsequent annotations can be chained.

You probably need to separate it into two steps.

Edit: The question has commented that that filters can be chained but annotations cannot.

like image 100
Dwight Gunning Avatar answered Oct 23 '22 03:10

Dwight Gunning