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中集合类型(set)学习小结
Jan 28 Python
Python列表解析配合if else的方法
Jun 23 Python
python实现linux下抓包并存库功能
Jul 18 Python
Pycharm以root权限运行脚本的方法
Jan 19 Python
python 列表转为字典的两个小方法(小结)
Jun 28 Python
python实现大文本文件分割
Jul 22 Python
django 做 migrate 时 表已存在的处理方法
Aug 31 Python
Python3使用xml.dom.minidom和xml.etree模块儿解析xml文件封装函数的方法
Sep 23 Python
Python使用Pandas读写Excel实例解析
Nov 19 Python
浅析Python3 pip换源问题
Jan 06 Python
python3 正则表达式基础廖雪峰
Mar 25 Python
pytorch 如何使用float64训练
May 24 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
windows环境下php配置memcache的具体操作步骤
2013/06/09 PHP
PHP常用设计模式之委托设计模式
2016/02/13 PHP
js中判断Object、Array、Function等引用类型对象是否相等
2012/08/29 Javascript
解析使用js判断只能输入数字、字母等验证的方法(总结)
2013/05/14 Javascript
JavaScript 函数惰性载入的实现及其优点介绍
2013/08/12 Javascript
在javascript中如何得到中英文混合字符串的长度
2014/01/17 Javascript
简介JavaScript中的sub()方法的使用
2015/06/08 Javascript
JS实现的简洁二级导航菜单雏形效果
2015/10/13 Javascript
jQuery中trigger()与bind()用法分析
2015/12/18 Javascript
原生JavaScript实现瀑布流布局
2020/06/28 Javascript
jQuery实现简单的DIV拖动效果
2016/02/19 Javascript
AngularJS中$apply方法和$watch方法用法总结
2016/12/13 Javascript
微信小程序商城项目之购物数量加减(3)
2017/04/17 Javascript
js实现关闭网页出现是否离开提示
2017/12/07 Javascript
Vue中Quill富文本编辑器的使用教程
2018/09/21 Javascript
微信小程序移动拖拽视图-movable-view实例详解
2019/08/17 Javascript
JavaScript使用表单元素验证表单的示例代码
2019/08/20 Javascript
angularjs模态框的使用代码实例
2019/12/20 Javascript
[01:22]DOTA2神秘商店携大量周边降临完美大师赛
2017/11/07 DOTA
Python中的一些陷阱与技巧小结
2015/07/10 Python
Python3结合Dlib实现人脸识别和剪切
2018/01/24 Python
python 实现对数据集的归一化的方法(0-1之间)
2018/07/17 Python
python config文件的读写操作示例
2019/09/27 Python
Python操作注册表详细步骤介绍
2020/02/05 Python
python实现人机五子棋
2020/03/25 Python
scrapy爬虫:scrapy.FormRequest中formdata参数详解
2020/04/30 Python
HTML5页面音视频在微信和app下自动播放的实现方法
2016/10/20 HTML / CSS
aden + anais官方网站:婴儿襁褓、毯子、尿布和服装
2017/06/21 全球购物
Club Monaco加拿大官网:设计师男女服装
2019/09/29 全球购物
Cecil Mode法国在线商店:女性时尚
2021/01/08 全球购物
日本AOKI官方商城:AOKI西装
2020/06/11 全球购物
介绍一下常见的木马种类
2014/11/15 面试题
2014年高二班主任工作总结
2014/12/16 职场文书
小学公民道德宣传日活动总结
2015/03/23 职场文书
小学感恩主题班会
2015/08/12 职场文书
Python scrapy爬取起点中文网小说榜单
2021/06/13 Python