使用Django实现把两个模型类的数据聚合在一起
作者:肾虚少年 发布时间:2023-11-11 23:37:42
Django中想要把模型类聚合得到想要的数据可以用F对象。
比如有模型类A和B,A和B之间有外键关联在一起,A是子表,B是父表(反过来没试过。。因为大部分数据都是用子表的,我想是可以的),那么可以这样查:
A.objects.filter(userid=3,bookid=F(bid))
其中userid,bookid是模型类A的字段,bid是模型类B的字段。
这样操作的结果就是可以查询到userid为3且模型类A字段bookid等于模型类B字段bid的集合数据了。
F对象是可以比较两个关联模型类的字段数据的。
我看到网上有说F对象可以这样用F('b__id') ==>F('模型类名小写__字段名'),此处是双下划线。
但是我用Django2.0时会报错。。真是搞不懂,后来我直接使用字段名居然可以,醉了。
反正都可以试试吧
A.objects.filter(userid=3,bookid=F(bid))
A.objects.filter(userid=3,bookid=F('b__bid'))
补充知识:Django Admin页面显示父表,编辑子表
默认情况下,ModelAdmin只允许您管理模型“本身”字段,而不是相关模型.以下方法将实现,在应用类的列表管理显示页面,显示父表的字段;在编辑页面,父表对子表进行编辑.
models.py如下
class Level(models.Model):
# l_num = models.IntegerField(default=0, verbose_name='序号')
name = models.CharField(max_length=20)
is_delete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Grades(models.Model):
name = models.CharField(max_length=20, verbose_name='班级')
# 外键,这里关联模型Level与模型名称一样,不是全小写。
level = models.ForeignKey('Level', on_delete=models.DO_NOTHING)
is_delete = models.BooleanField(default=False)
def __str__(self):
return '%s%s' % (self.level, self.name)
class Students(models.Model):
name = models.CharField(max_length=20, db_index=True, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
# 需要先提供一个二维的二元元组,第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体内容
SEX_CHOICE = (
('男', '男'),
('女', '女'),
)
sex = models.CharField(max_length=10, choices=SEX_CHOICE, verbose_name='性别', default='男')
grade = models.ForeignKey('Grades', on_delete=models.DO_NOTHING, verbose_name="班级")
img_student = models.ImageField(upload_to='img_student', default='img_student/default.png', verbose_name='头像')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
last_update_time = models.DateTimeField(auto_now=True, verbose_name='上次更新时间')
is_delete = models.BooleanField(default=False)
def __str__(self):
return self.name
在admin.py代码如下:
@admin.register(Students)
class StudentsAdmin(admin.ModelAdmin):
list_display = ('name', 'age', 'sex', 'grade', 'create_time', 'last_update_time', 'is_delete')
做完之后,显示的效果如下:
在应用类的列表管理显示页面,显示父表的字段
可以让Students,显示父表Grades的父表Level字段
在models.py里的Students类里,写上如下代码:
class Students(models.Model):
# 写一个方法,定义在管理页面上能够显示的外键字段字段
# grade为Students模型的外检表,level为Grades模型的外检表,那么为Level模型的字段
def dis_level(self):
return self.grade.level.name
# 定义该字段在管理后台显示的名称
dis_level.short_description = '年级'
# 定义该字段在管理后台显示的名称
dis_level.short_description = '年级'
# 方法列是不能排序的,如果需要排序需要为方法指定排序依据。添加的是'模型类字段'
# 如果是外键需要遵循这样的语法:本表外键字段__(双下划线)外检表字段或外检表的外键字段__最终外键表要显示的字段。
dis_level.admin_order_field = 'grade__level__name'
在admin.py里,把Students类里的方法,加入到list_display里:
@admin.register(Students)
class StudentsAdmin(admin.ModelAdmin):
list_display = ('name', 'age', 'sex', 'grade', 'dis_level', 'create_time', 'last_update_time', 'is_delete')
写完之后,显示的结果如下,多了年级,以及点击年级可以进行排序:
在编辑页面,父表对子表进行编辑.
默认对学生编辑时,无法在编辑页面直接编辑相关联的子表,例如:
models.py代码:
class Students(models.Model):
name = models.CharField(max_length=20, db_index=True, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
# 需要先提供一个二维的二元元组,第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体内容
SEX_CHOICE = (
('男', '男'),
('女', '女'),
)
sex = models.CharField(max_length=10, choices=SEX_CHOICE, verbose_name='性别', default='男')
grade = models.ForeignKey('Grades', on_delete=models.DO_NOTHING, verbose_name="班级")
img_student = models.ImageField(upload_to='img_student', default='img_student/default.png', verbose_name='头像')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
last_update_time = models.DateTimeField(auto_now=True, verbose_name='上次更新时间')
is_delete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Course(models.Model):
name = models.CharField(max_length=20, verbose_name='课名')
is_delete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Score(models.Model):
s_score = models.IntegerField(default=0, verbose_name='分数')
s_course = models.ForeignKey('Course', on_delete=models.DO_NOTHING, verbose_name='课程')
s_student = models.ForeignKey('Students', on_delete=models.DO_NOTHING, verbose_name='学生姓名')
is_delete = models.BooleanField(default=False)
def __str__(self):
# 要把s_score转换为字符串,否则会报下面的错误。
"""
Exception Type:TypeError
Exception Value:
__str__ returned non-string (type int)
:return:
"""
return '%s%s%s' % (self.s_student, self.s_course, str(self.s_score))
打开学生的编辑页面,是这样子的:
要给学生添加分数,只能进入Score管理页面,一个个添加,非常麻烦.
使用Django的TabularInline,可以解决这个问题,在父表里对子表进行编辑:
所有代码都在admin.py里写,具体如下:
# 一对多关联表编辑,让父表管理配置页面能同时编辑子表,以下的Score为子表(有外键所在的表)
class ScoreInline(admin.TabularInline):
# Score 必须是models.py中的模型名称,大小写必须要匹配.这个模型为子表,以便可以被父表编辑
model = Score
# 默认显示条目的数量
# extra = 5
class StudentsAdmin(admin.ModelAdmin):
# Inline把ScoreInline关联进来,让父表管理配置页面能同时编辑子表.
inlines = [ScoreInline, ]
做完之后,效果如下:
来源:https://blog.csdn.net/woshidamimi0/article/details/79795462


猜你喜欢
- 关于递归函数:函数内部调用自身的函数。以n阶乘为例:f(n) = n ! = 1 x 2 x 3 x 4 x...x(n-1)x(n) =
- 本文实例为大家分享了vuex实现购物车功能的具体代码,供大家参考,具体内容如下先看效果:代码:<template> <di
- 1.简介当一个表数据量很大时候,很自然我们就会想到将表拆分成很多小表,在执行查询时候就到各个小表去查,最后汇总数据集返回给调用者加快查询速度
- 目录结构:client:#!/usr/bin/env python# -*-coding:utf-8 -*-import socket, s
- 前言了解 Python 的都知道 Pyinstaller 可以将 .py 文件打包成 windows 下可执行的 .exe 文件, 但是在我
- 本文实例讲述了python中pycurl库的用法,分享给大家供大家参考。该实例代码实现从指定网址读取网页,主要是pycurl库的使用。具体实
- 经常在网上冲浪的朋友是否曾注意到有些网站的鼠标不是规则的斜向上箭头的形状,而是"十"
- 一 概念Django的ORM中存在查询集的概念。查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。当调用如下过滤器方法
- using System; using System.Data; using System.Configuration; using Sys
- 什么是 PIP?PIP 是 Python 包或模块的包管理器。注释:如果你使用的是 Python 3.4 或更高版本,则默认情况下会包含 P
- 前言ThinkPHP,是为了简化企业级应用开发和敏捷WEB应用开发而诞生的开源轻量级PHP框架。随着框架代码量的增加,一些潜在的威胁也逐渐暴
- 最近项目中需要与管易云erp做对接,看了他的接口文档,php的示例代码,于是用python仿写。其中传的参数data中前面几个json数据是
- 本文实例讲述了python面试题之列表声明。分享给大家供大家参考,具体如下:下面程序输出的结果为?val = [['a']*
- 前言前两篇我们分别爬取了糗事百科和妹子图网站,学习了 Requests, Beautiful Soup 的基本使用。不过前两篇都是从静态 H
- oracle10g数据备份 1.用sql/plus developer,选中要备份的数据表,右击选择"Export data&qu
- Python中创建线程有两种方式:函数或者用类来创建线程对象。函数式:调用 _thread 模块中的start_new_thread()函数
- 遇到这样一个情况想将变量v转化为[]string类型var v interface{}a := []interface{}{"1&
- 一、函数解释setdiff1d(ar1, ar2, assume_unique=False)1.功能:找到2个数组中集合元素的差异。2.返回
- 上一文写了如何从代理服务网站提取 IP,本文就讲解如何存储 IP,毕竟代理池还是要有一定量的 IP 数量才行。存储的方式有很多,直接一点的可
- 如下所示:# -*- coding: utf-8 -*-import sysfrom PyQt5.QtWidgets import (QAp