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 文件与目录操作
Dec 24 Python
浅谈Python中用datetime包进行对时间的一些操作
Jun 23 Python
对pandas中apply函数的用法详解
Apr 10 Python
Python 将pdf转成图片的方法
Apr 23 Python
python实现扫描局域网指定网段ip的方法
Apr 16 Python
Python flask框架post接口调用示例
Jul 03 Python
Django的用户模块与权限系统的示例代码
Jul 24 Python
python实现两个文件夹的同步
Aug 29 Python
Python 类方法和实例方法(@classmethod),静态方法(@staticmethod)原理与用法分析
Sep 20 Python
python opencv 实现读取、显示、写入图像的方法
Jun 08 Python
Matplotlib自定义坐标轴刻度的实现示例
Jun 18 Python
python实现A*寻路算法
Jun 13 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编写PDF文档生成器
2006/10/09 PHP
手把手教你使用DedeCms的采集的图文教程
2007/03/11 PHP
php获取指定范围内最接近数的方法
2015/06/02 PHP
Laravel框架实现redis集群的方法分析
2017/09/14 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
2017/11/14 PHP
PHP实现一个限制实例化次数的类示例
2019/09/16 PHP
JavaScript Cookie 直接浏览网站分网址
2009/12/08 Javascript
javascript forEach通用循环遍历方法
2010/10/11 Javascript
2014年50个程序员最适用的免费JQuery插件
2014/12/15 Javascript
jQuery实现表格颜色交替显示的方法
2015/03/09 Javascript
jQuery简单实现上下,左右滑动的方法
2016/06/01 Javascript
HTML中setCapture、releaseCapture 使用方法浅析
2016/09/25 Javascript
JavaScript对象封装的简单实现方法(3种方法)
2017/01/03 Javascript
Node.js中文件操作模块File System的详细介绍
2017/01/05 Javascript
微信小程序报错:this.setData is not a function的解决办法
2017/09/27 Javascript
使用layer弹窗和layui表单实现新增功能
2018/08/09 Javascript
vue进入页面时滚动条始终在底部代码实例
2019/03/26 Javascript
vue安装遇到的5个报错及解决方法
2019/06/12 Javascript
基于js实现数组相邻元素上移下移
2020/05/19 Javascript
详解Python字典小结
2018/10/20 Python
从0开始的Python学习014面向对象编程(推荐)
2019/04/02 Python
对PyQt5的输入对话框使用(QInputDialog)详解
2019/06/25 Python
python中利用numpy.array()实现俩个数值列表的对应相加方法
2019/08/26 Python
Django框架HttpRequest对象用法实例分析
2019/11/01 Python
Python使用type动态创建类操作示例
2020/02/29 Python
Python内置异常类型全面汇总
2020/05/28 Python
集体婚礼证婚词
2014/01/13 职场文书
读书活动实施方案
2014/03/10 职场文书
六个一活动实施方案
2014/03/21 职场文书
银行行长竞聘演讲稿
2014/04/23 职场文书
党性教育心得体会
2014/09/03 职场文书
场地使用证明模板
2014/10/25 职场文书
考试没考好检讨书(精选篇)
2014/11/16 职场文书
2014年民政工作总结
2014/11/26 职场文书
给老师的感谢信
2015/01/20 职场文书
2015年清明节演讲稿范文
2015/03/17 职场文书