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 19 Python
Python常用模块用法分析
Sep 08 Python
python3中dict(字典)的使用方法示例
Mar 22 Python
python实现图像识别功能
Jan 29 Python
PyTorch上实现卷积神经网络CNN的方法
Apr 28 Python
浅谈pandas用groupby后对层级索引levels的处理方法
Nov 06 Python
Python简单实现区域生长方式
Jan 16 Python
Python Sphinx使用实例及问题解决
Jan 17 Python
PyCharm 在Windows的有用快捷键详解
Apr 07 Python
Tensorflow tf.tile()的用法实例分析
May 22 Python
python单元测试之pytest的使用
Jun 07 Python
python的变量和简单数字类型详解
Sep 15 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开启gzip页面压缩实例
2013/06/09 PHP
Linux编译升级php的详细方法
2013/11/04 PHP
Laravel 5框架学习之Eloquent (laravel 的ORM)
2015/04/08 PHP
php封装的验证码类分享
2017/02/26 PHP
Jquery插件之打造自定义的select标签
2011/11/30 Javascript
jquery获得页面元素的坐标值实现思路及代码
2013/04/15 Javascript
JS关闭窗口与JS关闭页面的几种方法小结
2013/12/17 Javascript
Javascript控制input输入时间格式的方法
2015/01/28 Javascript
jQuery validate验证插件使用详解
2016/05/11 Javascript
Angularjs的ng-repeat中去除重复数据的方法
2016/08/05 Javascript
微信小程序 解决swiper不显示图片的方法
2017/01/04 Javascript
Vue.js:使用Vue-Router 2实现路由功能介绍
2017/02/22 Javascript
vue之nextTick全面解析
2017/05/17 Javascript
基于JavaScript中标识符的命名规则介绍
2018/01/06 Javascript
微信小程序实现弹出菜单功能
2018/06/12 Javascript
微信开发之企业付款到银行卡接口开发的示例代码
2018/09/18 Javascript
vue单页缓存存在的问题及解决方案(小结)
2018/09/25 Javascript
Vue的路由及路由钩子函数的实现
2019/07/02 Javascript
[02:35]DOTA2英雄基础教程 末日使者
2013/12/04 DOTA
在RedHat系Linux上部署Python的Celery框架的教程
2015/04/07 Python
apache部署python程序出现503错误的解决方法
2017/07/24 Python
Python探索之实现一个简单的HTTP服务器
2017/10/28 Python
python3大文件解压和基本操作
2017/12/15 Python
浅谈python爬虫使用Selenium模拟浏览器行为
2018/02/23 Python
解决nohup执行python程序log文件写入不及时的问题
2019/01/14 Python
python模块和包的应用BASE_PATH使用解析
2019/12/14 Python
美国网上花店:JustFlowers
2017/02/12 全球购物
英国邮购活的植物主要供应商:Gardening Direct
2019/01/28 全球购物
中软Java笔试题
2012/11/11 面试题
精细化工应届生求职信
2013/11/17 职场文书
2014年采购工作总结
2014/11/20 职场文书
学术会议通知范文
2015/04/15 职场文书
送达通知书
2015/04/25 职场文书
幼儿园2016年感恩节活动总结
2016/04/01 职场文书
手把手教你制定暑期学习计划,让你度过充实的暑假
2019/08/22 职场文书