ORM多表操作
一、ORM多表创建
一对多:关联字段必须创建在多的一方
多对多:创建第三张关联表
一对一:即一张大表拆分成多个小表,关系字段创建在任何一张表均可,需在关联字段上创建unique约束
from django.db import models from django.db.models import CharField,EmailField,AutoField,DateField,IntegerField,BigIntegerField,DecimalField,ForeignKey,OneToOneField,ManyToManyField # Create your models here. class AuthorDetail(models.Model): nid=AutoField(primary_key=True) birthday=DateField() telephone=BigIntegerField() addr=CharField(max_length=128) class Author(models.Model): nid=AutoField(primary_key=True) name=CharField(max_length=64) age=IntegerField() #一对一,相对于ForeignKey多一个unique约束 authordetial=OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) class Publish(models.Model): nid=AutoField(primary_key=True) name=CharField(max_length=64) city=CharField(max_length=64) email=EmailField() class Book(models.Model): nid=AutoField(primary_key=True) title=CharField(max_length=64) publishDate=DateField() price=DecimalField(max_digits=5,decimal_places=2) #一对多 publish=ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) #多对多,生成第三张表,不会在book表上添加新字段 authors=ManyToManyField(to="Author")
setting中设置数据库引擎为MySQL
DATABASES = { 'default':{ 'ENGINE':'django.db.backends.mysql', 'NAME':'orm2', 'USER':'root', 'PASSWORD':'123.com', 'HOST':'127.0.0.1', 'PORT':3306 } }
on_delete参数:
CASCADE:此值设置,是级联删除。
PROTECT:此值设置,是会报完整性错误。
SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
SET_DEFAULT:此值设置,会把设置为外键的默认值。
SET():此值设置,会调用外面的值,可以是一个函数。
一般情况下使用CASCADE就可以了
注意:
- 表名用为app_table
- 会自动添加ID字段,
- 对于外键字段,Django会自动添加上_id
- 在setting文件中注册app名称,否则迁移的时候不会成功
- 外键ForeignKey有个null=True的参数,他允许外键接受NULL,可以给赋空值None
多表数据添加
一对多:
方式一:
给publish_id赋值
def add(request): new_publish=Publish.objects.create(name="人民出版社",city="BeiJing",email="r@dd.com") new_book=Book.objects.create(title="西游记",price=100,publishDate="1890-12-1",publish_id=new_publish.nid)
方式二:
给publish赋值,非publish_id,不能直接赋一个ID值,需要赋值一个实例对象,实例对象通过QuerySet的first()或[0]的方式取得
publish=Publish.objects.filter(nid=7).first() new_book = Book.objects.create(title="水浒传", price=166, publishDate="1890-12-1", publish=publish)
无论哪种方式赋值添加,查询取得的publish都是是一个Publish对象,可以通过“.”获取相关属性
多对多:
通过“关联”字段对象add方法添加
方式一:
直接传入对象
方式二:
传入对象主键id
方式三:
传入对象主键id列表
#绑定多对多关系 new_book=Book.objects.create(title="红楼梦",price=200,publishDate="1990-1-1",publish_id=7) yaya=Author.objects.filter(name='yaya').first() huangya=Author.objects.filter(name="huangya").first() #给第三张关联表添加数据,即绑定对多对关系的API #方式一 new_book.authors.add(huangya,yaya) #方式二,传入主键 new_book.authors.add(1, 4) #方式三,传入主键列表 new_book.authors.add(*[1, 4])
解除关联关系
方式一:
obj.authors.remove(1,4)
方式一:
obj.authors.remove(*[1,4])
方式一:
obj.authors.remove(huangya,yaya)
方式四:
obj.authors.clear()清除所有多对多关系
new_book=Book.objects.get(nid=3) new_book.authors.remove(1) new_book.authors.remove(huangya)
注:
- 创建外键的时候,一定要注意实际Django在关联字段后面添加了_id
- 关联字段和被关联字段同时创建和关联时,如果关联失败,那么被关联表的数据不影响插入
二、多表数据查询
查询方向:关联属性在A表,那么通过A对象查询B,则为正向查询。通过B查询A则为反向查询
(一)、基于对象的跨表查询
相当于mysql的子查询
一对多:
正向查询:通过字段查询
#正向查询按字段 book_obj=Book.objects.filter(title='西游记').first() print(book_obj.publish.name)
反向查询:通过表名小写查询,固定语法,表名小写_set
#反向查询按表名 publish_obj=Publish.objects.filter(name='人民出版社').first() #返回一个QuerySet books=publish_obj.book_set.all() print(books)
多对多:
正向查询按字段查询,反向查询按表名小写查询。和一对多一样
正向查询:
#查询书籍的作者名称 book_obj=Book.objects.filter(title="红楼梦").first() #该书籍的所有作者集合,QuerySet对象 author_list=book_obj.authors.all() for author in author_list: print(author.name)
反向查询:
#反向查询 author_obj=Author.objects.filter(name='yaya').first() books=author_obj.book_set.all() for book in books: print(book.title)
一对一:
正向查询按字段,反向查询按表名小写,无_set,即非集合
正向查询:
author_obj=Author.objects.filter(name="huangya").first() #正向插叙 print(author_obj.authordetial.telephone)
反向查询:
#反向查询 detial_obj=AuthorDetail.objects.filter(telephone='17589742390').first() print(detial_obj.author.name)
(二)、基于双下划线的跨表查询
相当于mysql的join查询
正向查询按字段下旬,反向查询按表名小写查询。告知ORM引擎join那张表
一对多:
方式一,正向查询values:
无过滤条件
#SELECT app_publish.name,app_publish.city FROM app_book INNER JOIN app_publish res5=Book.objects.values('publish__name','publish__city')
添加过滤条件
#SELECT app_publish.name,app_publish.city FROM app_book INNER JOIN app_publish WHERE app_book.title="西游记" res=Book.objects.filter(title="西游记").values('publish__name','publish__city')
方式二,反向查询filter:
#SELECT app_publish.name,app_publish.city FROM app_publish INNER JOIN app_book ON app_publish.nid = app_book.publish_id WHERE app_book.title="西游记" Publish.objects.filter(book__title="西游记").values('name')
多对多:
查询《红楼梦》的作者
方式一、正向查询。通过book表join与其关联的author表
SQL: SELECT app_author.name from app_book INNER JOIN app_book_authors ON app_book.nid =app_book_authors.book_id INNER JOIN app_author ON app_book_authors.author_id = app_author.nid WHERE app_book.title="红楼梦" """ # ORM res=Book.objects.filter(title="红楼梦").values('authors__name')
方式二、反向查询。通过author表join与其关联的book表
Author.objects.filter(book__title="红楼梦").values('name')
一对一:
查询作者的电话号码
方式一:正向查询
Author.objects.filter(name="huangya").values('authordetial__telephone')
方式二:反向查询
AuthorDetail.objects.filter(author__name="huangya").values('telephone')
进阶查询
无关联,所以必须跨表查询
需求:查询手机号175开头的作者出版过的所有书籍名称以及书籍出版社名称。
方式一:
Book.objects.filter(authors__authordetial__telephone__startswith="175").values('title','publish__name')
方式二:
Author.objects.filter(authordetial__telephone__startswith='175').values("book__title","book__publish__name")
(三)、聚合查询
导入Django函数,from django.db.models import Avg,Max,Min,Count
查询所有书籍平均价格
SQL语句:
SELECT avg(price) as avg from app_book;
ORM:
Book.objects.all().aggregate(Avg('price'))
返回字典,并非QuerySet
自定义键
Book.objects.all().aggregate(priceAvg=Avg('price'))
查询最大值与最小值。也可以像Avg()一样自定义键
Book.objects.all().aggregate(Max('price'),Min('price'))
(四)、分组查询
(五)、F与Q查询