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 相关文章推荐
linux系统使用python监控apache服务器进程脚本分享
Jan 15 Python
Python编写生成验证码的脚本的教程
May 04 Python
编写Python脚本批量下载DesktopNexus壁纸的教程
May 06 Python
python处理Excel xlrd的简单使用
Sep 12 Python
浅析python协程相关概念
Jan 20 Python
浅谈配置OpenCV3 + Python3的简易方法(macOS)
Apr 02 Python
python 文本单词提取和词频统计的实例
Dec 22 Python
解决python super()调用多重继承函数的问题
Jun 26 Python
django 使用全局搜索功能的实例详解
Jul 18 Python
python脚本执行CMD命令并返回结果的例子
Aug 14 Python
python多进程间通信代码实例
Sep 30 Python
Jupyter notebook无法导入第三方模块的解决方式
Apr 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缩略图生成程式(需要GD库支持)
2007/03/06 PHP
Ajax+PHP边学边练 之五 图片处理
2009/12/03 PHP
PHP 开发环境配置(测试开发环境)
2010/04/28 PHP
php 对输入信息的进行安全过滤的函数代码
2012/06/29 PHP
php使用sql数据库 获取字段问题介绍
2013/08/12 PHP
一个基于phpQuery的php通用采集类分享
2014/04/09 PHP
php批量删除数据库下指定前缀的表以prefix_为例
2014/08/24 PHP
php接口技术实例详解
2016/12/07 PHP
服务器安全设置的几个注册表设置
2007/07/28 Javascript
js 无提示关闭浏览器页面的代码
2010/03/09 Javascript
Node.js:Windows7下搭建的Node.js服务(来玩玩服务器端的javascript吧,这可不是前端js插件)
2011/06/27 Javascript
Textarea根据内容自适应高度
2013/10/28 Javascript
JavaScript判断变量是对象还是数组的方法
2014/08/28 Javascript
学习JavaScript鼠标响应事件
2015/12/25 Javascript
设置点击文本框或图片弹出日历控件的实现代码
2016/05/12 Javascript
简单的分页代码js实现
2016/05/17 Javascript
jQuery焦点图轮播插件KinSlideshow用法分析
2016/06/08 Javascript
使用Promise链式调用解决多个异步回调的问题
2017/01/15 Javascript
jQuery插件Echarts实现的渐变色柱状图
2017/03/23 jQuery
JavaScript实现QQ列表展开收缩扩展功能
2017/10/30 Javascript
vue Cli 环境删除与重装教程 - 版本文档
2020/09/11 Javascript
[02:32]DOTA2英雄基础教程 祸乱之源
2013/12/23 DOTA
[04:23]DOTA2上海特锦赛小组赛第一日 TOP10精彩集锦
2016/02/27 DOTA
python生成词云的实现方法(推荐)
2017/06/13 Python
python自动登录12306并自动点击验证码完成登录的实现源代码
2018/04/25 Python
pandas数据清洗,排序,索引设置,数据选取方法
2018/05/18 Python
Django ORM 常用字段与不常用字段汇总
2019/08/09 Python
python os.path.isfile 的使用误区详解
2019/11/29 Python
解决Python列表字符不区分大小写的问题
2019/12/19 Python
Pandas实现DataFrame按行求百分数(比例数)
2019/12/27 Python
mac系统下安装pycharm、永久激活、中文汉化详细教程
2020/11/24 Python
基层干部十八大感言
2014/01/19 职场文书
数控技术专业毕业自荐书范文
2014/02/05 职场文书
师恩难忘教学反思
2014/04/27 职场文书
幼儿园健康教育方案
2014/06/14 职场文书
Meta增速拉垮,元宇宙难当重任
2022/04/29 数码科技