Django annotate query set with a count on subquery

后端 未结 2 572
星月不相逢
星月不相逢 2021-02-04 06:59

This doesn\'t seem to work in django 1.1 (I believe this will require a subquery, therefore comes the title)

qs.annotate(interest_level= \\
             Count(Q(         


        
2条回答
  •  醉梦人生
    2021-02-04 07:10

    Looking at the add_aggregate function within django/db/models/sql/query.py, query objects will not be accepted as input values.

    Unfortunately, there is currently no direct way within Django to aggregate/annotate on what amounts to a queryset, especially not one that is additionally filtered somehow.

    Assuming the following models:

    class Item(models.Model):
        name = models.CharField(max_length=32)
    
    class Tag(models.Model):
        itemfk = models.ForeignKey(Item, related_name='tags')
        name = models.CharField(max_length=32)
    
    class FavoritedTag(models.Model):
        user = models.ForeignKey(User)
        tag = models.ForeignKey(Tag)
    

    Also, you cannot annotate a queryset on fields defined via .extra().

    One could drop into SQL in views.py like so:

    from testing.models import Item, Tag, FavoritedTag
    from django.shortcuts import render_to_response
    from django.contrib.auth.decorators import login_required
    from django.utils.datastructures import SortedDict
    
    @login_required
    def interest_level(request):
        ruid = request.user.id
    
        qs = Item.objects.extra(
            select = SortedDict([
                ('interest_level', 'SELECT COUNT(*) FROM testing_favoritedtag, testing_tag \
                WHERE testing_favoritedtag.user_id = %s \
                AND testing_favoritedtag.tag_id = testing_tag.id \
                AND testing_tag.itemfk_id = testing_item.id'),
            ]),
            select_params = (str(ruid),)
        )
    
        return render_to_response('testing/interest_level.html', {'qs': qs})
    

    Template:

    {% for item in qs %}
        name: {{ item.name }}, level: {{ item.interest_level }}
    {% endfor %}

    I tested this using MySQL5. Since I'm no SQL expert though, I'd be curious as to how to optimize here, or if there is another way to "lessen" the amount of SQL. Maybe there is some interesting way to utilize the related_name feature here directly within SQL?

提交回复
热议问题