代码之家  ›  专栏  ›  技术社区  ›  simplyharsh

如何在Django中查询分组依据?

  •  256
  • simplyharsh  · 技术社区  · 16 年前

    我查询一个模型,

    Members.objects.all()
    

    它回来说

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

    我想要的是,知道最好的射击方法 对我的数据库进行分组查询,就像,

    Members.objects.all().group_by('designation')
    

    当然不行。 我知道我们可以在“django/db/models/query.py”上做一些技巧。 但我只是好奇如何做到不打补丁。

    9 回复  |  直到 7 年前
        1
  •  391
  •   jb.    8 年前

    如果要进行聚合,可以使用 aggregation features of the ORM :

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

    这将导致类似于

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

    输出的形式是

    [{'designation': 'Salesman', 'dcount': 2}, 
     {'designation': 'Manager', 'dcount': 2}]
    
        2
  •  40
  •   Kris Kumler    13 年前

    一个简单的解决方案是使用raw-sql,但方法不正确:

    http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql

    另一种解决方案是使用分组依据属性:

    query = Members.objects.all().query
    query.group_by = ['designation']
    results = QuerySet(query=query, model=Members)
    

    现在可以迭代results变量来检索结果。请注意,Group_by没有文档记录,可能会在未来的Django版本中更改。

    还有…为什么要使用分组依据?如果不使用聚合,则可以使用order-by来获得相同的结果。

        3
  •  10
  •   inostia    7 年前

    您也可以使用 regroup 按属性分组的模板标记。来自文档:

    cities = [
        {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
        {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
        {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
        {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
        {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
    ]
    
    ...
    
    {% regroup cities by country as country_list %}
    
    <ul>
        {% for country in country_list %}
            <li>{{ country.grouper }}
                <ul>
                {% for city in country.list %}
                    <li>{{ city.name }}: {{ city.population }}</li>
                {% endfor %}
                </ul>
            </li>
        {% endfor %}
    </ul>
    

    如下所示:

    • 印度
      • 孟买:19000000
      • 加尔各答:15000000
    • 美国
      • 纽约:20000000
      • 芝加哥:70万
    • 日本
      • 东京:33000000

    它也适用于 QuerySet 我相信。

    来源: https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#regroup

        4
  •  5
  •   Van Gale    16 年前

    您需要按照以下代码段中的示例执行自定义SQL:

    Custom SQL via subquery

    或者在自定义管理器中,如在线django文档所示:

    Adding extra Manager methods

        5
  •  4
  •   Risadinha    9 年前

    有一个模块允许您对django模型进行分组,并在结果中使用一个查询集: https://github.com/kako-nawao/django-group-by

    例如:

    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)
    

    '书籍/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>
    

    不同于 annotate / aggregate Django基本查询是使用相关字段的属性,例如 book.author.last_name .

    如果需要组合在一起的实例的pk,请添加以下注释:

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

    注: ArrayAgg 是Postgres特定功能,从Django 1.9起提供: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayagg

        6
  •  3
  •   Luis Masuelli    10 年前

    Django不支持自由分组查询 . 我是以非常糟糕的方式学会的。ORM的设计不支持您想做的事情,而不使用自定义SQL。您仅限于:

    • 原始SQL(即myModel.objects.raw())
    • cr.execute 句子(以及对结果的手工分析)。
    • .annotate() (group by语句在.annotate()的子模型中执行,例如聚合行\u count=count(“lines”))。

    在一个查询集上 qs 你可以打电话 qs.query.group_by = ['field1', 'field2', ...] 但是,如果您不知道正在编辑的查询是什么,并且不能保证它可以工作,并且不能破坏queryset对象的内部,那么这是有风险的。此外,它是一个内部(未记录的)API,您不应该在不冒代码不再与未来的Django版本兼容的风险的情况下直接访问它。

        7
  •  0
  •   ramwin    8 年前

    这个 document 表示可以使用值对查询集进行分组。

    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
    

    您可以找到所有书籍,并使用以下代码按名称分组:

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

    你可以看一些厚棉布 here .

        8
  •  -1
  •   Reed Jones    11 年前

    如果我没有误以为你可以用, 任何查询集 GROPPYB= 领域 ''

        9
  •  -3
  •   Kiran S youtube channel    7 年前
    from django.db.models import Sum
    Members.objects.annotate(total=Sum(designation))
    

    首先您需要导入SUM 然后…