How to query as GROUP BY in django?

前端 未结 9 1254
别跟我提以往
别跟我提以往 2020-11-22 05:40

I query a model:

Members.objects.all()

And it returns:

Eric, Salesman, X-Shop
Freddie, Manager, X2-Shop
Teddy, Salesman, X2         


        
相关标签:
9条回答
  • 2020-11-22 06:02

    The following module allows you to group Django models and still work with a QuerySet in the result: https://github.com/kako-nawao/django-group-by

    For example:

    from django_group_by import GroupByMixin
    
    class BookQuerySet(QuerySet, GroupByMixin):
        pass
    
    class Book(Model):
        title = TextField(...)
        author = ForeignKey(User, ...)
        shop = ForeignKey(Shop, ...)
        price = DecimalField(...)
    

    class GroupedBookListView(PaginationMixin, ListView):
        template_name = 'book/books.html'
        model = Book
        paginate_by = 100
    
        def get_queryset(self):
            return Book.objects.group_by('title', 'author').annotate(
                shop_count=Count('shop'), price_avg=Avg('price')).order_by(
                'name', 'author').distinct()
    
        def get_context_data(self, **kwargs):
            return super().get_context_data(total_count=self.get_queryset().count(), **kwargs)
    

    'book/books.html'

    <ul>
    {% for book in object_list %}
        <li>
            <h2>{{ book.title }}</td>
            <p>{{ book.author.last_name }}, {{ book.author.first_name }}</p>
            <p>{{ book.shop_count }}</p>
            <p>{{ book.price_avg }}</p>
        </li>
    {% endfor %}
    </ul>
    

    The difference to the annotate/aggregate basic Django queries is the use of the attributes of a related field, e.g. book.author.last_name.

    If you need the PKs of the instances that have been grouped together, add the following annotation:

    .annotate(pks=ArrayAgg('id'))
    

    NOTE: ArrayAgg is a Postgres specific function, available from Django 1.9 onwards: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayagg

    0 讨论(0)
  • 2020-11-22 06:03

    If you mean to do aggregation you can use the aggregation features of the ORM:

    from django.db.models import Count
    Members.objects.values('designation').annotate(dcount=Count('designation'))
    

    This results in a query similar to

    SELECT designation, COUNT(designation) AS dcount
    FROM members GROUP BY designation
    

    and the output would be of the form

    [{'designation': 'Salesman', 'dcount': 2}, 
     {'designation': 'Manager', 'dcount': 2}]
    
    0 讨论(0)
  • 2020-11-22 06:09

    The document says that you can use values to group the queryset .

    class Travel(models.Model):
        interest = models.ForeignKey(Interest)
        user = models.ForeignKey(User)
        time = models.DateTimeField(auto_now_add=True)
    
    # Find the travel and group by the interest:
    
    >>> Travel.objects.values('interest').annotate(Count('user'))
    <QuerySet [{'interest': 5, 'user__count': 2}, {'interest': 6, 'user__count': 1}]>
    # the interest(id=5) had been visited for 2 times, 
    # and the interest(id=6) had only been visited for 1 time.
    
    >>> Travel.objects.values('interest').annotate(Count('user', distinct=True)) 
    <QuerySet [{'interest': 5, 'user__count': 1}, {'interest': 6, 'user__count': 1}]>
    # the interest(id=5) had been visited by only one person (but this person had 
    #  visited the interest for 2 times
    

    You can find all the books and group them by name using this code:

    Book.objects.values('name').annotate(Count('id')).order_by() # ensure you add the order_by()
    

    You can watch some cheet sheet here.

    0 讨论(0)
提交回复
热议问题