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 文件和输入输出小结
Oct 09 Python
python生成随机验证码(中文验证码)示例
Apr 03 Python
用Python编写一个国际象棋AI程序
Nov 28 Python
Python 多线程实例详解
Mar 25 Python
Python多进程写入同一文件的方法
Jan 14 Python
实例详解Python模块decimal
Jun 26 Python
解析python实现Lasso回归
Sep 11 Python
python生成requirements.txt的两种方法
Sep 18 Python
Python 读取 YUV(NV12) 视频文件实例
Dec 09 Python
python字符串拼接+和join的区别详解
Dec 03 Python
python中tkinter复选框使用操作
Nov 11 Python
python神经网络 tf.name_scope 和 tf.variable_scope 的区别
May 04 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 判断常量,变量和函数是否存在
2009/04/26 PHP
php微信开发之上传临时素材
2016/06/24 PHP
workerman结合laravel开发在线聊天应用的示例代码
2018/10/30 PHP
Laravel框架基于ajax实现二级联动功能示例
2019/01/17 PHP
深入理解JavaScript高级之词法作用域和作用域链
2013/12/10 Javascript
Jquery 实现table样式的设定
2015/01/28 Javascript
jquery使用slideDown实现模块缓慢拉出效果的方法
2015/03/27 Javascript
JavaScript实现自动生成网页元素功能(按钮、文本等)
2015/11/21 Javascript
jQuery简单实现tab选项卡切换效果
2016/06/20 Javascript
jQuery插件ajaxFileUpload使用实例解析
2016/10/19 Javascript
JavaScript基于replace+正则实现ES6的字符串模版功能
2017/04/25 Javascript
Vue三种常用传值示例(父传子、子传父、非父子)
2018/07/24 Javascript
JS调用安卓手机摄像头扫描二维码
2018/10/16 Javascript
在移动端使用vue-router和keep-alive的方法示例
2018/12/02 Javascript
JavaScript创建防篡改对象的方法分析
2018/12/30 Javascript
vue+webpack dev本地调试全局样式引用失效的解决方案
2019/11/12 Javascript
简单了解JavaScript sort方法
2019/11/25 Javascript
javascript实现点击星星小游戏
2019/12/24 Javascript
JS实现吸顶特效
2020/01/08 Javascript
解决echarts 一条柱状图显示两个值,类似进度条的问题
2020/07/20 Javascript
python正则分组的应用
2013/11/10 Python
python实现中文输出的两种方法
2015/05/09 Python
python实现RSA加密(解密)算法
2016/02/17 Python
python机器学习理论与实战(四)逻辑回归
2018/01/19 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
html5视频媒体标签video的使用方法及完整参数说明详解
2019/09/27 HTML / CSS
英国汽车和货车租赁网站:Hertz英国
2016/09/02 全球购物
Groupon比利时官方网站:特卖和网上购物高达-70%
2019/08/09 全球购物
eBay比利时购物网站:eBay.be
2019/08/09 全球购物
会计主管岗位职责范文
2013/11/08 职场文书
志愿者服务感言
2014/02/27 职场文书
五好关工委申报材料
2014/05/31 职场文书
优秀家长自荐材料
2014/08/26 职场文书
2015军训通讯稿大全
2015/07/18 职场文书
初中语文教学随笔
2015/08/15 职场文书
海贼王十大逆天果实 魂魂果实上榜,岩浆果实攻击力最强
2022/03/18 日漫