zoukankan      html  css  js  c++  java
  • django group by

    django group by

    概要

    如何用 django 自带的 ORM 框架来完成 SQL 中的 group by 操作呢?

    group-by


    环境介绍

    foo 这个应用定义了如下模型。

    class PersonModel(models.Model):
        name = models.CharField('姓名', max_length=64)
        age = models.PositiveIntegerField('年龄')
    
        def __str__(self):
            return f"{self.name} - {self.age}"
    

    数据库层面看到的表结构如下。

    CREATE TABLE `foo_personmodel` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL,
      `age` int(10) unsigned NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB
    

    表中的数据如下。

    mysql> select * from foo_personmodel;
    +----+-------+-----+
    | id | name  | age |
    +----+-------+-----+
    |  1 | tim   |  16 |
    |  2 | jerry |  27 |
    |  3 | marry |  18 |
    |  4 | tim   |  20 |
    |  5 | alis  |  17 |
    +----+-------+-----+
    5 rows in set (0.00 sec)
    

    全表聚合

    一个常见的需求,查询一下表中有多少行数据。

    SQL 写法。

    mysql> select count(id) as counts from foo_personmodel;
    +--------+
    | counts |
    +--------+
    |      5 |
    +--------+
    1 row in set (0.00 sec)
    

    ORM 实现。

    from django.db.models import Count
    from apps.foo.models import PersonModel
    
    PersonModel.objects.aggregate(counts = Count(id))
    
    {'counts': 5}
    

    注意 aggregate 返回的不再是 queryset 而是一个字典。


    values 方法

    要查询出每一行 name 列的取值。

    SQL 写法。

    mysql> select name from foo_personmodel;
    +-------+
    | name  |
    +-------+
    | tim   |
    | jerry |
    | marry |
    | tim   |
    | alis  |
    +-------+
    5 rows in set (0.00 sec)
    

    ORM 实现。

    PersonModel.objects.values("name")
    <QuerySet [{'name': 'tim'}, {'name': 'jerry'}, {'name': 'marry'}, {'name': 'tim'}, {'name': 'alis'}]>
    

    django 会返回一个 queryset 并且不会去重。


    分组聚合

    查询同一个名字在表中出现了多少次。

    SQL 写法。

    mysql> select name,count(id) as counts from foo_personmodel group by name;
    +-------+--------+
    | name  | counts |
    +-------+--------+
    | tim   |      2 |
    | jerry |      1 |
    | marry |      1 |
    | alis  |      1 |
    +-------+--------+
    4 rows in set (0.00 sec)
    

    ORM 写法。

    PersonModel.objects.values("name").annotate(counts=Count(id))
    <QuerySet [{'name': 'tim', 'counts': 2}, {'name': 'jerry', 'counts': 1}, {'name': 'marry', 'counts': 1}, {'name': 'alis', 'counts': 1}]>
    

    神奇的事情发生了,当 values 和 annotate 一起使用的时候,values 就承担起了 group by 的角色。并且自动去掉了重项!


    结论

    django 中并没有为 group by 设置单独的方法,而是通过 values + annotate 的组合来实现的。

  • 相关阅读:
    远程仓库拉取项目到本地并修改提交
    Django之URLconf路由
    Django简介以及安装
    Web开发介绍
    Python与MySQL数据库连接
    PyCharm快捷键
    python爬取有道翻译
    Vue相关知识总结
    Ajax相关介绍
    CSS中的定位
  • 原文地址:https://www.cnblogs.com/JiangLe/p/12668020.html
Copyright © 2011-2022 走看看