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系列之浅谈pickle模块封装和拆封数据对象的方法
May 23 Python
Python中使用语句导入模块或包的机制研究
Mar 30 Python
Python中tell()方法的使用详解
May 24 Python
浅谈python对象数据的读写权限
Sep 12 Python
python交互式图形编程实例(三)
Nov 17 Python
Python使用win32 COM实现Excel的写入与保存功能示例
May 03 Python
python pandas 如何替换某列的一个值
Jun 09 Python
python二维码操作:对QRCode和MyQR入门详解
Jun 24 Python
Python 日期的转换及计算的具体使用详解
Jan 16 Python
Python中 Global和Nonlocal的用法详解
Jan 20 Python
django有哪些好处和优点
Sep 01 Python
关于Python OS模块常用文件/目录函数详解
Jul 01 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 静态变量与自定义常量的使用方法
2010/01/26 PHP
PHP开发中四种查询返回结果分析
2011/01/02 PHP
深入Memcache的Session数据的多服务器共享详解
2013/06/13 PHP
ThinkPHP之R方法实例详解
2014/06/20 PHP
ThinkPHP中调用PHPExcel的实现代码
2017/04/08 PHP
php实现的mongoDB单例模式操作类
2018/01/20 PHP
Yii2框架数据验证操作实例详解
2018/05/02 PHP
一页面多XMLHttpRequest对象
2007/01/22 Javascript
javascript 网页跳转的方法
2008/12/24 Javascript
jQuery ul标签下拉菜单演示代码
2010/12/11 Javascript
javascript跨域刷新实现代码
2011/01/01 Javascript
jquery实现弹出层遮罩效果的简单实例
2014/03/03 Javascript
JavaScript基础重点(必看)
2016/07/09 Javascript
JavaScript微信定位功能实现方法
2016/11/29 Javascript
Vue2.0设置全局样式(less/sass和css)
2017/11/18 Javascript
React diff算法的实现示例
2018/04/20 Javascript
记一次用ts+vuecli4重构项目的实现
2020/05/21 Javascript
[01:06:54]DOTA2-DPC中国联赛 正赛 SAG vs DLG BO3 第二场 2月28日
2021/03/11 DOTA
Jupyter安装nbextensions,启动提示没有nbextensions库
2020/04/23 Python
Linux下多个Python版本安装教程
2018/08/15 Python
python面试题之列表声明实例分析
2019/07/08 Python
python如何导入依赖包
2020/07/13 Python
HTML5的download属性详细介绍和使用实例
2014/04/23 HTML / CSS
Debenhams百货英国官方网站:Debenhams UK
2016/07/12 全球购物
乌克兰在线电子产品商店:MTA
2019/11/14 全球购物
生产部岗位职责范文
2014/02/07 职场文书
2014年电教工作总结
2014/12/19 职场文书
董事长秘书岗位职责
2015/02/13 职场文书
先进个人总结范文
2015/02/15 职场文书
工资证明格式模板
2015/06/12 职场文书
小学英语教学随笔
2015/08/14 职场文书
Html分层的box-shadow效果的示例代码
2021/03/30 HTML / CSS
如何利用python和DOS获取wifi密码
2021/03/31 Python
MySQL中CURRENT_TIMESTAMP的使用方式
2021/11/27 MySQL
Django框架中表单的用法
2022/06/10 Python
Python docx库删除复制paragraph及行高设置图片插入示例
2022/07/23 Python