Django多层嵌套ManyToMany字段ORM操作详解


Posted in Python onMay 19, 2020

在用django写项目时,遇到了许多场景,关于ORM操作获取数据的,但是不好描述出来,百度搜索关键词都不知道该怎么搜,导致一个人鼓捣了好久。这里细化下问题,还原场景,记录踩下的坑

首先先列举model,我举些生活中的例子,更方便理解问题

# 习题
class Problem(models.Model):
  desc = models.CharField()
  answer = models.TextField()
  is_pass = models.BooleanField(default=False, verbose_name="是否通过")

# 章节
class Chapter(models.Model):
  _id = models.IntegerField(verbose_name="编号")
  title = models.CharField()
  problem = models.ManyToManyField(Problem)
  pass_rate = models.IntegerField(verbose_name="通关率")

# 书籍  
class Book(models.Model):
  title = models.CharField()
  desc = models.TextField()
  chapter = models.ManyToManyField(Chapter,verbose_name="章节")
  speed = models.IntegerField(verbose_name="学习进度", default=0)

假设是一本数学书,有5个章节,每个章节里有数量不等的习题,

即book与chapter是多对多,chapter与problem也是多对多

场景一: 书籍下的所有习题

# 按我的理解是取问题非空的章节数
# 类似于问爷爷有几个孙子,没办法跨辈,就按一个孙子对应一个爸爸来取(有重复)
book.chapter.filter(problem___id__isnull=False).count()

场景二:书籍下所有通过的习题

book.chapter.filter(problem__is_pass=True).count()

场景三: 判断某个问题是否在这本书里

def problem_in_ladder(book, problem):
    for i in book.chapter.all():
      if problem in i.problem.all():
        return True
    return False

尽可能的减少view中对models的取值操作,所以把上面几个场景方法写在models类中

最终的models

# 习题
class Problem(models.Model):
  desc = models.CharField()
  answer = models.TextField()
  is_pass = models.BooleanField(default=False, verbose_name="是否通过")

# 章节
class Chapter(models.Model):
  _id = models.IntegerField(verbose_name="编号")
  title = models.CharField()
  problem = models.ManyToManyField(Problem)
  pass_rate = models.IntegerField(verbose_name="通关率")
 
  @property
  def items(self):
    return self.problem.count()

  @property
  def pass_problem(self):
    return self.problem.filter(is_pass=True).count()
  
# 书籍  
class Book(models.Model):
  title = models.CharField()
  desc = models.TextField()
  chapter = models.ManyToManyField(Chapter,verbose_name="章节")
  speed = models.IntegerField(verbose_name="学习进度", default=0)
  
  @property
  def chapters(self):
    return self.chapter.count()

  @property
  def pass_count(self):
    return self.chapter.filter(problem__is_pass=True).count()

  @property
  def items(self):
    return self.chapter.filter(problem___id__isnull=False).count()

补充知识:django中当model设置了ordering后,使用distinct()和annotate()问题记录

model类如下,我在class Meta中设置了ordering = ['-date_create'],即模型对象返回的记录结果集是按照这个字段排序的。

class SystemUserPushHistory(models.Model):
 
  id = models.UUIDField(default=uuid.uuid4, primary_key=True)
  host_name = models.CharField(max_length=128, null=False)
  system_username = models.CharField(max_length=128, null=False)
  method = models.CharField(max_length=32, null=False)
  is_success = models.BooleanField(default=False)
  date_create = models.DateTimeField(auto_now_add=True, editable=False)
  message = models.CharField(max_length=4096, null=True)
 
  class Meta:
    db_table = "assets_systemuser_push_history"
    ordering = ['-date_create']
 
  def __str__(self):
    ret = self.system_username + " => " + self.host_name
    return ret

当业务有需求如对host_name进行分组显示,在代码中用到了annotate,如下。

>>> from django.db.models import Count 
>>> from assets.models import SystemUserPushHistory
>>> p = SystemUserPushHistory.objects.values("host_name").annotate(dcount=Count(1))
>>> p
<QuerySet [{'host_name': '点2', 'dcount': 1}, {'host_name': '点3', 'dcount': 2}, {'host_name': '点2', 'dcount': 1}, {'host_name': '点3', 'dcount': 1}]>
>>> print(p.query)
SELECT `assets_systemuser_push_history`.`host_name`, COUNT(1) AS `dcount` FROM `assets_systemuser_push_history` GROUP BY `assets_systemuser_push_history`.`host_name`, `assets_systemuser_push_history`.`date_create` ORDER BY `assets_systemuser_push_history`.`date_create` DESC

可以看到,所得到的结果并不像我们预期的一样,之后把执行的sql输出出来可以看到在group by的时候是对host_name和date_create进行分组,原因就是因为我们在model类中设置了ordering,去掉之后代码运行正常。

使用distinct和上面的情况类似,就不列出来了。

以上这篇Django多层嵌套ManyToMany字段ORM操作详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python文件与目录操作实例详解
Feb 22 Python
不同版本中Python matplotlib.pyplot.draw()界面绘制异常问题的解决
Sep 24 Python
Python实现常见的回文字符串算法
Nov 14 Python
关于Pycharm无法debug问题的总结
Jan 19 Python
利用pyinstaller打包exe文件的基本教程
May 02 Python
Python Django框架实现应用添加logging日志操作示例
May 17 Python
Python实现的企业粉丝抽奖功能示例
Jul 26 Python
python数据类型之间怎么转换技巧分享
Aug 20 Python
在Python中实现函数重载的示例代码
Dec 12 Python
3种python调用其他脚本的方法
Jan 06 Python
Python HTTP下载文件并显示下载进度条功能的实现
Apr 02 Python
Pycharm 使用 Pipenv 新建的虚拟环境(图文详解)
Apr 16 Python
django ORM之values和annotate使用详解
May 19 #Python
基于python实现地址和经纬度转换
May 19 #Python
Python Django form 组件动态从数据库取choices数据实例
May 19 #Python
Django自关联实现多级联动查询实例
May 19 #Python
Python的Django框架实现数据库查询(不返回QuerySet的方法)
May 19 #Python
django 数据库返回queryset实现封装为字典
May 19 #Python
使用PyQt的QLabel组件实现选定目标框功能的方法示例
May 19 #Python
You might like
鸡肋的PHP单例模式应用详解
2013/06/03 PHP
Laravel使用memcached缓存对文章增删改查进行优化的方法
2016/10/08 PHP
PHP实现十进制、二进制、八进制和十六进制转换相关函数用法分析
2017/04/25 PHP
PHP中的Iterator迭代对象属性详解
2019/04/12 PHP
jquery的ajax从纯真网(cz88.net)获取IP地址对应地区名
2009/12/02 Javascript
Wordpress ThickBox 添加“查看原图”效果代码
2010/12/11 Javascript
Jquery实现三层遍历删除功能代码
2013/04/23 Javascript
Javascript字符串浏览器兼容问题分析
2014/12/01 Javascript
基于javascript实现判断移动终端浏览器版本信息
2014/12/09 Javascript
jQuery实现列表内容的动态载入特效
2015/08/08 Javascript
AngularJs实现ng1.3+表单验证
2015/12/10 Javascript
jquery实现树形菜单完整代码
2015/12/29 Javascript
网页挂马方式整理及详细介绍
2016/11/03 Javascript
javascript中活灵活现的Array对象详解
2016/11/30 Javascript
bootstrap表格分页实例讲解
2016/12/30 Javascript
angular+webpack2实战例子
2017/05/23 Javascript
AngularJS 控制器 controller的详解
2017/10/17 Javascript
Nodejs把接收图片base64格式保存为文件存储到服务器上
2018/09/26 NodeJs
利用d3.js力导布局绘制资源拓扑图实例教程
2019/01/08 Javascript
微信小程序--特定区域滚动到顶部时固定的方法
2019/04/28 Javascript
微信小程序实现授权登录
2019/05/15 Javascript
微信小程序页面间传递数组对象方法解析
2019/11/06 Javascript
使用Karma做vue组件单元测试的实现
2020/01/16 Javascript
Python中的单行、多行、中文注释方法
2018/07/19 Python
Selenium控制浏览器常见操作示例
2018/08/13 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
Python学习笔记之列表推导式实例分析
2019/08/13 Python
Keras 中Leaky ReLU等高级激活函数的用法
2020/07/05 Python
Python爬虫之Selenium设置元素等待的方法
2020/12/04 Python
英国标志性奢侈品牌:Burberry
2016/07/28 全球购物
汽车驾驶求职信
2013/10/25 职场文书
企业法人授权委托书范本
2014/09/23 职场文书
2014幼儿园保育员工作总结
2014/11/10 职场文书
2015年幼儿园学期工作总结
2015/05/22 职场文书
JVM钩子函数的使用场景详解
2021/08/23 Java/Android
Window server 2012 R2 AD域的组策略相关设置
2022/04/28 Servers