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中使用smtplib和email模块发送邮件实例
Apr 22 Python
Python中map和列表推导效率比较实例分析
Jun 17 Python
Windows中安装使用Virtualenv来创建独立Python环境
May 31 Python
玩转python selenium鼠标键盘操作(ActionChains)
Apr 12 Python
Python3 伪装浏览器的方法示例
Nov 23 Python
python实现k-means聚类算法
Feb 23 Python
python2和python3的输入和输出区别介绍
Nov 20 Python
Python实现将通信达.day文件读取为DataFrame
Dec 22 Python
python图的深度优先和广度优先算法实例分析
Oct 26 Python
python与mysql数据库交互的实现
Jan 06 Python
使用Dajngo 通过代码添加xadmin用户和权限(组)
Jul 03 Python
Python 多进程、多线程效率对比
Nov 19 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下实现折线图效果的代码
2007/04/28 PHP
php自定义函数call_user_func和call_user_func_array详解
2011/07/14 PHP
ThinkPHP中RBAC类的四种用法分析
2014/11/24 PHP
ThinkPHP设置禁止百度等搜索引擎转码(简单实用)
2016/02/15 PHP
php 在字符串指定位置插入新字符的简单实现
2016/06/28 PHP
php有效防止图片盗用、盗链的两种方法
2016/11/01 PHP
php的4种常用运行方式详解
2016/12/22 PHP
求得div 下 img的src地址的js代码
2007/02/28 Javascript
JavaScript中也使用$美元符号来代替document.getElementById
2010/06/19 Javascript
Wordpress ThickBox 添加“查看原图”效果代码
2010/12/11 Javascript
JavaScript bold方法入门实例(把指定文字显示为粗体)
2014/10/17 Javascript
node.js中的http.get方法使用说明
2014/12/14 Javascript
JS及PHP代码编写八大排序算法
2016/07/12 Javascript
Jquery Easyui分割按钮组件SplitButton使用详解(17)
2016/12/18 Javascript
javascript 开发之网页兼容各种浏览器
2017/09/28 Javascript
Vue.js devtool插件安装后无法使用的解决办法
2017/11/27 Javascript
详解Vue.js中引入图片路径的几种方式
2019/06/17 Javascript
在webstorm中配置less的方法详解
2020/09/25 Javascript
使用Python对SQLite数据库操作
2017/04/06 Python
Python模拟鼠标点击实现方法(将通过实例自动化模拟在360浏览器中自动搜索python)
2017/08/23 Python
对numpy中array和asarray的区别详解
2018/04/17 Python
python 筛选数据集中列中value长度大于20的数据集方法
2018/06/14 Python
Python3.0 实现决策树算法的流程
2019/08/08 Python
python3调用windows dos命令的例子
2019/08/14 Python
Pandas实现dataframe和np.array的相互转换
2019/11/30 Python
python 操作hive pyhs2方式
2019/12/21 Python
python实现计算图形面积
2021/02/22 Python
简单的HTML5初步入门教程
2015/09/29 HTML / CSS
嘻哈珠宝品牌:KRKC&CO
2020/10/19 全球购物
工业自动化毕业生自荐信范文
2014/01/04 职场文书
聚美优品恶搞广告词
2014/03/14 职场文书
欢度春节标语
2014/07/01 职场文书
公共场所禁烟倡议书
2014/08/30 职场文书
师德承诺书
2015/01/20 职场文书
自主招生英文自荐信
2015/03/25 职场文书
四十年同学聚会致辞
2015/07/28 职场文书