Django annotate a field value to queryset

2019-08-12 05:37发布

I want to attach a field value (id) to a QS like below, but Django throws a 'str' object has no attribute 'lookup' error.

Book.objects.all().annotate(some_id='somerelation__id')

It seems I can get my id value using Sum()

Book.objects.all().annotate(something=Sum('somerelation__id'))

I'm wondering is there not a way to simply annotate raw field values to a QS? Using sum() in this case doesn't feel right.

2条回答
We Are One
2楼-- · 2019-08-12 05:49

You have <somerelation>_id "by default". For example comment.user_id. It works because User has many Comments. But if Book has many Authors, what author_id supposed to be in this case?

查看更多
放我归山
3楼-- · 2019-08-12 06:02

There are at least three methods of accessing related objects in a queryset.

  1. using Django's double underscore join syntax:
    If you just want to use the field of a related object as a condition in your SQL query you can refer to the field field on the related object related_object with related_object__field. All possible lookup types are listed in the Django documentation under Field lookups.

    Book.objects.filter(related_object__field=True)
    
  2. using annotate with F():
    You can populate an annotated field in a queryset by refering to the field with the F() object. F() represents the field of a model or an annotated field.

    Book.objects.annotate(added_field=F("related_object__field"))
    
  3. accessing object attributes: Once the queryset is evaluated, you can access related objects through attributes on that object.

    book = Book.objects.get(pk=1)
    author = book.author.name  # just one author, or…
    authors = book.author_set.values("name")  # several authors 
    

    This triggers an additional query unless you're making use of select_related().

My advice is to go with solution #2 as you're already halfway down that road and I think it'll give you exactly what you're asking for. The problem you're facing right now is that you did not specify a lookup type but instead you're passing a string (somerelation_id) Django doesn't know what to do with.

Also, the Django documentation on annotate() is pretty straight forward. You should look into that (again).

查看更多
登录 后发表回答