九、多表模型创建,一对一,一对多,基于对像的多表模型等
环境:
django1.9环境:
settings.py,注释csrf,并且设置使用mysql数据库
数据库的对应关系图:
一、多表模型创建,一对多增删改查,多对多增删改查
一对多:
models.py
总结:
#用了OneToOneField和ForeignKey,模型表的字段,后面会自定加_id
# ManyToManyField会自动创建第三张表
# *************重点
# 一对一的关系:OneToOneField
# 一对多的关系:ForeignKey
# 多对多的关系:ManyToManyField
# id如果不写,会自动生成,名字叫nid,并且自增(数据库类型不同,生成的名字也会随之不同)
from django.db import models# Create your models here.
class Publish(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=32)addr = models.CharField(max_length=64)email = models.EmailField()class AuthorDetail(models.Model):id = models.AutoField(primary_key=True)phone = models.CharField(max_length=32)addr = models.CharField(max_length=64)class Author(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=16)# 数字类型sex = models.IntegerField()# # to='AuthorDetail' 加引号,这个表能找到就可以,不用引号,类必须在上面定义authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')def __str__(self):return self.nameclass Book(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=32)price = models.DecimalField(max_digits=5, decimal_places=2)publish = models.ForeignKey(to=Publish, to_field='id')authors = models.ManyToManyField(to=Author)def __str__(self):return self.name
python3 manage makemigrations
python3 manage migrate
二、添加表记录
在11-13数据库中的app01_publish表中添加出版社数据:
在项目的根下添加test.py文件
import os
if __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pro11_13.settings")import djangodjango.setup()from app01.models import *# 以上代码是属于如何让py文件在django环境中运行 # 一对多新增数据# 添加一本北京出版社出版的书# 第一种方式ret=Book.objects.create(name='红楼梦',price=34.5,publish_id=1)print(ret.name)# 红楼梦
然后在book表中就会出先之前插入的数据。
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pro11_13.settings")import djangodjango.setup()from app01.models import *# 第二种方式,存对象publish=出版社的对象,存到数据库,是一个idpublish=Publish.objects.filter(pk=2).first()ret = Book.objects.create(name='西游记', price=34.5, publish=publish)print(ret.name)# 西游记
一对一修改数据:
方式一:
book=Book.objects.get(pk=1)
book.publish=出版社对象
book.publish_id=2
book.save()
方式二:
book=Book.objects.filter(pk=1).update(publish=出版社对象)
# book=Book.objects.filter(pk=1).update(publish_id=1)
多对多新增:
首先在数据中添加作者与作者详情
# 为红楼梦这本书新增一个叫lqz,egon的作者
方式一:
lqz=Author.objects.filter(name='lqz').first()
egon=Author.objects.filter(name='egon').first()
book=Book.objects.filter(name='红楼梦').first()
# add 添加多个对象
book.authors.add(lqz,egon
方式二:(为了测试,先把app01_book_authors表中的数据全部删除)
book=Book.objects.filter(name='红楼梦').first()
book.authors.add(1,2)
多对多删除:
方式一:
# remove,可以传对象,可以传id,可以传多个,不要混着用
lqz=Author.objects.filter(name='lqz').first()
book=Book.objects.filter(name='红楼梦').first()
book.authors.remove(lqz)
方式二:
lqz=Author.objects.filter(name='lqz').first()
egon=Author.objects.filter(name='egon').first()
book=Book.objects.filter(name='红楼梦').first()
book.authors.remove(1)
# book.authors.remove(1,2)
# clear清空所有
# book.authors.clear()
多对多修改:
# set,先清空,在新增,要传一个列表,列表内可以是, id,也可以是对象
原来表中的数据:
lqz=Author.objects.filter(name='lqz').first()
egon=Author.objects.filter(name='egon').first()
book=Book.objects.filter(name='红楼梦').first()
book.authors.set([2,])
# 或者:
# book.authors.set([lqz,])
修改之后:
错误方式:
********这样不行,因为它打散了传过去了,相当于book.authors.set(lqz)
# book.authors.set(*[lqz,])
总结:
添加表记录
1 一对多新增
-两种方式:
-publish=对象
-publish_id=id
2 一对多删除:同单表删除
3 一对多修改:两种方式,可以传对象,可以传id
4 一对一跟一对多一样
5 多对多:
-add ----->可以传对象,可以传id,可以传多个
-remove ----->可以传对象,可以传id,可以传多个
-clear ---->没有参数
-set ----->跟上面不一样,必须传列表,列表里面可以是对象,可以是id
三、基于对象的跨表查询,一对一,一对多,多对多查询
1 一对一
正向:正向查询按字段,(author---关联字段在author--->authordetail ------> 按字段)
# 查询egon作者的手机号 正向查询
author=Author.objects.filter(name='egon').first()
authordetail=author.authordetail
print(authordetail.phone)
---------------------------------
13513513561
反向:反向查询按表名小写,(authordetail------关联字段在author--->author -----> 按表名小写)
# 查询地址是 :山东 的作者名字 反向查询
authordetail=AuthorDetail.objects.filter(addr=' 上海').first()
author = authordetail.author
print(author.name)
----------------------------
egon
2 一对多
正向:正向查询按字段。(拿书查出版社信息)
正向 book---关联字段在book--->publish ------> 按字段
正向 查询红楼梦这本书的出版社邮箱
book=Book.objects.filter(name='红楼梦').first()
pulish=book.publish
print(pulish.email)
-------------------
564@qq.com
反向:反向按表名小写_set.all()
反向 publish------关联字段在book--->book -----> 按表名小写_set.all()(拿出版社信息查询图书)。
反向 查询地址是北京 的出版社出版的图书
publish=Publish.objects.filter(addr='北京').first()
books=publish.book_set.all() # publish.book_set.all() 拿出所有的图书
print(books)
--------------------
<QuerySet [<Book: 红楼梦>]>
# 统计一下条数
books=publish.book_set.all().count()
print(books)
-----------------
1
3 多对多
正向:正向查询按字段
正向 book---关联字段在book--->author ------> 按字段.all()
#查询红楼梦这本书所有的作者
book=Book.objects.filter(name='红楼梦').first()
print(book.authors.all()) # 是所有的作者,是一个queryset对象,可以继续点
---------------------------------------------
<QuerySet [<Author: egon>]>
反向查询:反向按表名小写_set.all()
反向 author------关联字段在book--->book -----> 按表名小写_set.all()
# 查询lqz写的所有书
egon=Author.objects.filter(name='egon').first()
books=egon.book_set.all()
print(books)
------------------------------------------------------
<QuerySet [<Book: 红楼梦>]>
# 连续跨表
# 查询红楼梦这本书所有的作者的手机号
book=Book.objects.filter(name='红楼梦').first()
authors=book.authors.all()for author in authors:authordetail=author.authordetailprint(authordetail.phone)
-----------------------------------------
13513513561
四、******基于对象的查询,是子查询也就是多次查询)
*********************基于双下划线的查询***************
# 一对一
# 查询lqz作者的手机号 正向查询 跨表的话,按字段
# 以author表作为基表
ret=Author.objects.filter(name='egon').values('authordetail__phone')
print(ret)
------------------------------
<QuerySet [{'authordetail__phone': '13513513561'}]>
# 以authordetail作为基表
# 反向查询,按表名小写 跨表的话,用表名小写
ret=AuthorDetail.objects.filter(author__name='egon').values('phone')
print(ret)
---------------------------------------------
<QuerySet [{'phone': '13513513561'}]>
# 查询lqz这个作者的性别和手机号
# 正向
ret=Author.objects.filter(name='egon').values('sex','authordetail__phone')
print(ret)
-------------------------
<QuerySet [{'sex': 1, 'authordetail__phone': '13513513561'}]>
# 查询手机号是13513513561的作者性别
ret=Author.objects.filter(authordetail__phone='13513513561').values('sex')
print(ret)
-------------------------------------
<QuerySet [{'sex': 1}]>
ret=AuthorDetail.objects.filter(phone='13513513561').values('author__sex')
print(ret)
-------------------------
<QuerySet [{'author__sex': 1}]>
五、基于双下划线的一对多查询
# 查询出版社为北京出版社出版的所有图书的名字,价格
ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price')
print(ret)
----------------------------------------------------------------------
<QuerySet [{'book__name': '红楼梦', 'book__price': Decimal('34.50')}, {'book__name': '西游记', 'book__price': Decimal('553.30')}]>
------------------------------------------------------------------------
ret=Book.objects.filter(publish__name='北京出版社').values('name','price')
print(ret)
-----------------------------------------------------
<QuerySet [{'name': '红楼梦', 'price': Decimal('34.50')}, {'name': '西游记', 'price': Decimal('553.30')}]># 反向查询
# 查询北京出版社出版的价格大于19的书
ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name','book__price')
print(ret)
-----------------------------------------------------
<QuerySet [{'book__name': '红楼梦', 'book__price': Decimal('34.50')}, {'book__name': '西游记', 'book__price': Decimal('553.30')}]>
六、基于双下划线的多对多查询
# 查询红楼梦的所有作者名字
ret=Book.objects.filter(name='红楼梦').values('authors__name')
print(ret)
--------------------------
<QuerySet [{'book__name': '红楼梦', 'book__price': Decimal('34.50')}, {'book__name': '西游记', 'book__price': Decimal('553.30')}]>
-----------------------------------------------------------
ret=Author.objects.filter(book__name='红楼梦').values('name')
print(ret)
------------------------------------------------------------------
<QuerySet [{'name': 'egon'}]>
# 查询图书价格大于30的所有作者名字
ret=Book.objects.filter(price__gt=30).values('authors__name')
print(ret)
---------------------------------
<QuerySet [{'authors__name': 'egon'}, {'authors__name': None}]>
# 进阶练习--连续跨表# 查询北京出版社出版过的所有书籍的名字以及作者的姓名
ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
print(ret)
----------------------------------------
<QuerySet [{'book__name': '红楼梦', 'book__authors__name': 'egon'}, {'book__name': '西游记', 'book__authors__name': None}]>
----------------------------------------------------------
ret=Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
print(ret)
---------------------------------------
<QuerySet [{'name': '红楼梦', 'authors__name': 'egon'}, {'name': '西游记', 'authors__name': None}]># 手机号以135开头的作者出版过的所有书籍名称以及出版社名称
ret=AuthorDetail.objects.filter(phone__startswith='135').values('author__book__name','author__book__publish__name')
print(ret)
--------------------------------------------------
<QuerySet [{'author__book__name': '红楼梦', 'author__book__publish__name': '北京出版社'}]>
---------------------------------------------------------------------
ret=Book.objects.filter(authors__authordetail__phone__startswith='135').values('name','publish__name')
print(ret)
-----------------------------------------------------------------------
<QuerySet [{'name': '红楼梦', 'publish__name': '北京出版社'}]>
# 聚合查询aggregate
from django.db.models import Avg,Count,Max,Min,Sum
# 计算所有图书的平均价格
ret=Book.objects.all().aggregate(Avg('price'))
print(ret)
-----------------------
{'price__avg': 293.9}# 计算图书的最高价格
ret=Book.objects.all().aggregate(Max('price'))
print(ret)
------------------------------------
{'price__max': Decimal('553.30')}#他是queryset的终止子句
# 计算图书的最高价格,最低价格,平均价格,总价
ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price'))
print(ret)
---------------------------------------------
{'price__max': Decimal('553.30'), 'price__min': Decimal('34.50'), 'price__avg': 293.9, 'price__sum': Decimal('587.80')}# 分组查询annotate()
# 统计每一本书作者个数
ret=Book.objects.all().annotate(c=Count('authors'))
print(ret)
for r in ret:print(r.name,'---->',r.c)
----------------------------------------------
<QuerySet [<Book: 红楼梦>, <Book: 西游记>]>
红楼梦 ----> 1
西游记 ----> 0
---------------------------------------------
ret=Book.objects.all().annotate(c=Count('authors')).values('name','c')
print(ret)
------------------------------------
<QuerySet [{'name': '红楼梦', 'c': 1}, {'name': '西游记', 'c': 0}]># 统计每一个出版社的最便宜的书(以谁group by 就以谁为基表)
ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m')
print(ret)
------------------------------------------
<QuerySet [{'name': '北京出版社', 'm': Decimal('34.50')}]>
# 统计每一本以py开头的书籍的作者个数
ret=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')
print(ret)
--------------------------------
<QuerySet [{'name': 'py书大全', 'c': 0}]># 总结: group by 谁,就以谁做基表,filter过滤,annotate取分组,values取值# 总结终极版本# values在前,表示group by 在后,表示取值# filter在前,表示where条件,在后表示having# 统计每一本以py开头的书籍的作者个数--套用模板
ret=Book.objects.all().values('name').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')
print(ret)
-----------------------------------
<QuerySet [{'name': 'py书大全', 'c': 0}]># 查询各个作者出的书的总价格
ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s')
print(ret)
--------------------------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s')
print(ret)
----------------------------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]># 查询名字叫egon作者书的总价格
ret=Author.objects.all().values('pk').filter(name='egon').annotate(s=Sum('book__price')).values('name','s')
print(ret)
-----------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]># 查询所有作者写的书的总价格大于30
ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s')
print(ret)
-----------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=30).values('name','s')
print(ret)
-------------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]># 总结终极版本
# values在前,表示group by 在后,表示取值
# filter在前,表示where条件,在后表示having# 统计不止一个作者的图书
ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num')
ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c')
print(ret)
七、F函数
models.py
from django.db import models# Create your models here.#用了OneToOneField和ForeignKey,模型表的字段,后面会自定加_id
# ManyToManyField会自动创建第三张表
# *************重点
# 一对一的关系:OneToOneField
# 一对多的关系:ForeignKey
# 多对多的关系:ManyToManyFieldclass Publish(models.Model):# id如果不写,会自动生成,名字叫nid,并且自增id = models.AutoField(primary_key=True)name = models.CharField(max_length=32)addr = models.CharField(max_length=64)email = models.EmailField()class Author(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=32)# 数字类型sex = models.IntegerField()# 可以用ForeignKey,但是得设置唯一性约束,会报警告,不建议用,建议用OneToOneField# authordetail=models.ForeignKey(unique=True)# to='AuthorDetail' 加引号,这个表能找到就可以,不用引号,类必须在上面定义authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')def __str__(self):return self.nameclass AuthorDetail(models.Model):id = models.AutoField(primary_key=True)phone = models.CharField(max_length=32)addr = models.CharField(max_length=64)class Book(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=32,db_index=True)price = models.DecimalField(max_digits=5, decimal_places=2)# 阅读数reat_num=models.IntegerField(default=0)# 评论数commit_num=models.IntegerField(default=0)publish = models.ForeignKey(to=Publish, to_field='id',on_delete=models.CASCADE)authors = models.ManyToManyField(to=Author)# test=models.PositiveSmallIntegerField()def __str__(self):return self.nameclass Test(models.Model):name=models.CharField(max_length=32)class Meta:db_table='aaa'
python3 manage makemigrations
python3 manage migrate
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day77.settings")import djangodjango.setup()from app01.models import *
from django.db.models import F
# 查询评论数大于阅读数的书
ret=Book.objects.all().filter(commit_num__gt=F('reat_num'))
print(ret)
---------------------------------
<QuerySet [<Book: 红楼梦>]># 把所有书的评论数加100
ret=Book.objects.all().update(commit_num=F("commit_num")+100)
print(ret)# 把红楼梦这本书的阅读数减5
ret = Book.objects.all().filter(name='红楼梦').update(reat_num=F('reat_num') - 5)
print(ret)# Q函数 为了表示与& ,或 | ,非 ~,
from django.db.models import Q
# 查询作者不是lqz的书
ret=Book.objects.filter(~Q(authors__name='lqz'))
print(ret)
<QuerySet [<Book: 红楼梦>, <Book: 西游记>, <Book: py书大全>]>
# 构建很复杂的逻辑,需要用括号来区分
ret = Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100)) | Q(pk__gt=2))
print(ret)
------------------------------
<QuerySet [<Book: py书大全>]>
总结:
1基于双下划线的跨表查询套路一样,用__跨表-一对多-多对多2 聚合查询-聚合函数from django.db.models import Avg,Count,Max,Min,Sum# 计算所有图书的平均价格# ret=Book.objects.all().aggregate(Avg('price'))# print(ret)3分组查询终极总结:values在前,表示group by,在后,表示取值filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)4 F查询与Q查询-F为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了-Q为了构造与&,或|,非~的关系5 常用字段:必须记住,非常用字段,了解即可6 orm字段参数:-null 可以为空-unique 唯一性约束-default 默认值-db_index 为该字段建索引-只给日期类型和时间类型用-auto_now_add 新增数据时,默认把当前时间存入-auto_now 修改的时候,默认把当前时间存入7 关系字段ForeignKey-to 关联哪个表-to_field 关联的字段-related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。(一般不要用)-related_query_name :基于双下划线的反向查询之前按表名小写(一般不要用)-on_delete:models.CASCADE,models.SET_NULL-db_constraint:db_constraint=False代表,不做外键关联作业:1 手动创建第三张表,并且新增,删除,查询数据2 整理博客3 上课讲的敲一遍
转载于:https://blog.51cto.com/silencezone/2361369
九、多表模型创建,一对一,一对多,基于对像的多表模型等相关推荐
- bim 模型web页面展示_基于HTML5/WebGL技术的BIM模型轻量化Web浏览解决方案
互联网技术的兴起极大得改变了我们的娱乐.生活和生产方式.尤其是HTML5/WebGL技术的发展更是在各个行业内引起颠覆性的变化,大家感受最深刻的可能是游戏.电商.O2O等和我们生活息息相关的行业,但这 ...
- 数据表的创建(一对多,多对多)
前言 项目开发过程中,数据库表会出现很多映射关系,不只有一对多,还有一对多,多对多.则数据库实体间有三种对应关系:一对一,一对多,多对多. 一.实例 一对一关系实例: 一个学生对应一个学号. 一对多关 ...
- Oracle系列之七:表的创建与管理
Oracle表的创建与管理 1. 表的创建 2. 表的修改 3. 表中数据的增删改查 4. 表的Merge 5. 表的删除 6. 表的重命名 7. 表的索引 8. 表的约束 9. dual表 表是Or ...
- 数据库、表的创建与修改
目录 一.实验目的 1.实验6.6 MySQL安装创建和维护数据库实验 2.实验7.8 数据表的创建与修改管理实验 二.实验内容 1.验证性实验 三.设计性实验 四.实验小结: 一.实验目的 1.实验 ...
- 3dsmax 模型创建+原生贴图+obj/mtl+three.js 实现WEB3D
3dsmax模型创建+原生贴图 模型创建请参考另一篇我的文章 3dsmax 模型创建+原生贴图(多图) 为何要原生贴图? 因为three.js只支持原生贴图的obj/mtl文件 obj/mtl导出 T ...
- BIM研究-基于HTML5/WebGL技术的BIM模型轻量化Web浏览解决方案
内容来源:http://developer.51cto.com/art/201601/504553.htm 根据运维系统的特点,运维人员可能并不熟悉建筑建模软件的使用,同时让运维人员使用建模软件来做运 ...
- mysql-表关系模型,一对一,一对多,多对多
一对一关系模型 >生活实例: 民政局登记的数据表,是一对一的关系 一公民,只能够有一位合法的配偶 >操作 民政局会有一个表 字段会有 主键id,男方身份证号,女方身份证号 然后会往表中插入 ...
- mysql 树形结构_结合RBAC模型讲解权限管理系统需求及表结构创建
结合RBAC模型讲解权限管理系统需求及表结构创建 在本号之前的文章中,已经为大家介绍了很多关于Spring Security的使用方法,也介绍了RBAC的基于角色权限控制模型.但是很多朋友虽然已经理解 ...
- 7. MyBatis多表查询 - 一对一 - 一对多 - 多对多
7. MyBatis多表查询 - 一对一 - 一对多 - 多对多 前言 在前面的篇章,我们已经熟悉了单表查询,下面我们来看看如何进行 多表查询. 数据准备 create database if not ...
最新文章
- 关于python中的dict和defaultdict
- 人类正在进入超级智能时代,论一种新超级智能的崛起
- 码上公益首秀,让科技更有温度!
- 有三AI不得不看的几十篇技术综述
- SQL语句中,创建标识列、默认值及各种约束的语法介绍
- 配置V530交换机步骤
- 14岁女孩模仿视频中易拉罐做爆米花意外身亡 博主办公室小野回应...
- 这款老不死的笔记本,产品小姐姐的最爱......
- 蛮力法 —— 求解最大连续子序列和问题
- 普通用户登录PLSQL后提示空白OK对话框错误
- 前端高效开发必备的 js 库大全
- windows11 安全中心点击进去内容空白解决方法
- 在哪里能看到计算机缓存大小,怎么查看电脑硬盘缓存大小
- JavaScript实现人民币大小写转换
- Android 调用谷歌原生语音识别
- git常用命令梳理及常见开发场景总结
- linux 内存使用计算
- FleaPHP 开发指南 - 7. 数据表关联
- alibaba的druid连接池的监控的两种方法
- MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位