九、多表模型创建,一对一,一对多,基于对像的多表模型等
環(huán)境:
django1.9環(huán)境:
settings.py,注釋csrf,并且設(shè)置使用mysql數(shù)據(jù)庫
數(shù)據(jù)庫的對應(yīng)關(guān)系圖:
一、多表模型創(chuàng)建,一對多增刪改查,多對多增刪改查
一對多:
models.py
總結(jié):
#用了OneToOneField和ForeignKey,模型表的字段,后面會自定加_id
# ManyToManyField會自動創(chuàng)建第三張表
# *************重點
# 一對一的關(guān)系:OneToOneField
# 一對多的關(guān)系:ForeignKey
# 多對多的關(guān)系:ManyToManyField
# id如果不寫,會自動生成,名字叫nid,并且自增(數(shù)據(jù)庫類型不同,生成的名字也會隨之不同)
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)#?數(shù)字類型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.namepython3 manage makemigrations
python3 manage migrate
二、添加表記錄
在11-13數(shù)據(jù)庫中的app01_publish表中添加出版社數(shù)據(jù):
在項目的根下添加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環(huán)境中運行?#?一對多新增數(shù)據(jù)#?添加一本北京出版社出版的書#?第一種方式ret=Book.objects.create(name='紅樓夢',price=34.5,publish_id=1)print(ret.name)#?紅樓夢然后在book表中就會出先之前插入的數(shù)據(jù)。
一對一修改數(shù)據(jù):
方式一:
方式二:
多對多新增:
首先在數(shù)據(jù)中添加作者與作者詳情
# 為紅樓夢這本書新增一個叫l(wèi)qz,egon的作者
方式一:
方式二:(為了測試,先把app01_book_authors表中的數(shù)據(jù)全部刪除)
多對多刪除:
方式一:
# remove,可以傳對象,可以傳id,可以傳多個,不要混著用
lqz=Author.objects.filter(name='lqz').first() book=Book.objects.filter(name='紅樓夢').first() book.authors.remove(lqz)方式二:
多對多修改:
# ?set,先清空,在新增,要傳一個列表,列表內(nèi)可以是, id,也可以是對象
原來表中的數(shù)據(jù):
修改之后:
錯誤方式:
********這樣不行,因為它打散了傳過去了,相當(dāng)于book.authors.set(lqz) #?book.authors.set(*[lqz,])總結(jié):
添加表記錄
?? ??? ?1 一對多新增
?? ??? ??? ?-兩種方式:
?? ??? ??? ??? ?-publish=對象
?? ??? ??? ??? ?-publish_id=id
?? ??? ?2 一對多刪除:同單表刪除
?? ??? ?3 一對多修改:兩種方式,可以傳對象,可以傳id
?? ??? ?4 一對一跟一對多一樣
?? ??? ?5 多對多:
?? ??? ??? ?-add? ----->可以傳對象,可以傳id,可以傳多個
?? ??? ??? ?-remove? ----->可以傳對象,可以傳id,可以傳多個
?? ??? ??? ?-clear? ---->沒有參數(shù)
?? ??? ??? ?-set?? ----->跟上面不一樣,必須傳列表,列表里面可以是對象,可以是id
三、基于對象的跨表查詢,一對一,一對多,多對多查詢
????????1 一對一
?? ??? ??? ?正向:正向查詢按字段,(author---關(guān)聯(lián)字段在author--->authordetail?? ------>? 按字段)
?? ??? ???? ?# 查詢egon作者的手機號?? 正向查詢
author=Author.objects.filter(name='egon').first() authordetail=author.authordetail print(authordetail.phone) --------------------------------- 13513513561????????????反向:反向查詢按表名小寫,(authordetail------關(guān)聯(lián)字段在author--->author? -----> 按表名小寫)
????????????#? 查詢地址是 :山東 的作者名字?? 反向查詢
authordetail=AuthorDetail.objects.filter(addr='?上海').first() author?=?authordetail.author print(author.name) ---------------------------- egon?? ???? 2 一對多
?? ??? ??? ?正向:正向查詢按字段。(拿書查出版社信息)
????????????正向?? book---關(guān)聯(lián)字段在book--->publish?? ------>? 按字段
????????????正向 查詢紅樓夢這本書的出版社郵箱
book=Book.objects.filter(name='紅樓夢').first() pulish=book.publish print(pulish.email) ------------------- 564@qq.com?? ??? ???? 反向:反向按表名小寫_set.all()
????????????反向?? publish------關(guān)聯(lián)字段在book--->book? -----> 按表名小寫_set.all()(拿出版社信息查詢圖書)。
????????????反向? 查詢地址是北京 的出版社出版的圖書
publish=Publish.objects.filter(addr='北京').first() books=publish.book_set.all()??#?publish.book_set.all()??拿出所有的圖書 print(books) -------------------- <QuerySet?[<Book:?紅樓夢>]> #?統(tǒng)計一下條數(shù) books=publish.book_set.all().count() print(books) ----------------- 1?? ???? 3 多對多
?? ??? ??? ?正向:正向查詢按字段
????????????正向?? book---關(guān)聯(lián)字段在book--->author?? ------>? 按字段.all()
????????????#查詢紅樓夢這本書所有的作者
book=Book.objects.filter(name='紅樓夢').first() print(book.authors.all())???#?是所有的作者,是一個queryset對象,可以繼續(xù)點 --------------------------------------------- <QuerySet?[<Author:?egon>]>?? ??? ???? 反向查詢:反向按表名小寫_set.all()
????????????反向?? author------關(guān)聯(lián)字段在book--->book? -----> 按表名小寫_set.all()
????????????# 查詢lqz寫的所有書
egon=Author.objects.filter(name='egon').first() books=egon.book_set.all() print(books) ------------------------------------------------------ <QuerySet?[<Book:?紅樓夢>]>?# 連續(xù)跨表
?# 查詢紅樓夢這本書所有的作者的手機號
四、******基于對象的查詢,是子查詢也就是多次查詢)
*********************基于雙下劃線的查詢***************
# 一對一
# 查詢lqz作者的手機號?? 正向查詢? 跨表的話,按字段
# 以author表作為基表
# 以authordetail作為基表
# 反向查詢,按表名小寫? 跨表的話,用表名小寫
ret=AuthorDetail.objects.filter(author__name='egon').values('phone') print(ret) --------------------------------------------- <QuerySet?[{'phone':?'13513513561'}]># 查詢lqz這個作者的性別和手機號
# 正向
# 查詢手機號是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')}]>六、基于雙下劃線的多對多查詢
# 聚合查詢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() #?統(tǒng)計每一本書作者個數(shù) 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}]>#?統(tǒng)計每一個出版社的最便宜的書(以誰group?by?就以誰為基表) ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m') print(ret) ------------------------------------------ <QuerySet?[{'name':?'北京出版社',?'m':?Decimal('34.50')}]> #?統(tǒng)計每一本以py開頭的書籍的作者個數(shù) ret=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') print(ret) -------------------------------- <QuerySet?[{'name':?'py書大全',?'c':?0}]>#?總結(jié):??group?by?誰,就以誰做基表,filter過濾,annotate取分組,values取值#?總結(jié)終極版本#?values在前,表示group?by?在后,表示取值#?filter在前,表示where條件,在后表示having#?統(tǒng)計每一本以py開頭的書籍的作者個數(shù)--套用模板 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')}]>#?總結(jié)終極版本 #?values在前,表示group?by?在后,表示取值 #?filter在前,表示where條件,在后表示having#?統(tǒng)計不止一個作者的圖書 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函數(shù)
models.py
from?django.db?import?models#?Create?your?models?here.#用了OneToOneField和ForeignKey,模型表的字段,后面會自定加_id #?ManyToManyField會自動創(chuàng)建第三張表 #?*************重點 #?一對一的關(guān)系:OneToOneField #?一對多的關(guān)系:ForeignKey #?多對多的關(guān)系: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)#?數(shù)字類型sex?=?models.IntegerField()#?可以用ForeignKey,但是得設(shè)置唯一性約束,會報警告,不建議用,建議用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)#?閱讀數(shù)reat_num=models.IntegerField(default=0)#?評論數(shù)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
總結(jié):
1基于雙下劃線的跨表查詢套路一樣,用__跨表-一對多-多對多2?聚合查詢-聚合函數(shù)from?django.db.models?import?Avg,Count,Max,Min,Sum#?計算所有圖書的平均價格#?ret=Book.objects.all().aggregate(Avg('price'))#?print(ret)3分組查詢終極總結(jié):values在前,表示group?by,在后,表示取值filter在前,表示過濾(where),在后,表示having(對分組之后的結(jié)果再進(jìn)行過濾)4?F查詢與Q查詢-F為了字段=后面的值,不能放字段,所以用F函數(shù)包裹一下就可以了-Q為了構(gòu)造與&,或|,非~的關(guān)系5?常用字段:必須記住,非常用字段,了解即可6?orm字段參數(shù):-null??可以為空-unique??唯一性約束-default?默認(rèn)值-db_index?為該字段建索引-只給日期類型和時間類型用-auto_now_add????新增數(shù)據(jù)時,默認(rèn)把當(dāng)前時間存入-auto_now????????修改的時候,默認(rèn)把當(dāng)前時間存入7?關(guān)系字段ForeignKey-to??關(guān)聯(lián)哪個表-to_field?關(guān)聯(lián)的字段-related_name?反向操作時,使用的字段名,用于代替原反向查詢時的'表名_set'。(一般不要用)-related_query_name?:基于雙下劃線的反向查詢之前按表名小寫(一般不要用)-on_delete:models.CASCADE,models.SET_NULL-db_constraint:db_constraint=False代表,不做外鍵關(guān)聯(lián)作業(yè):1?手動創(chuàng)建第三張表,并且新增,刪除,查詢數(shù)據(jù)2?整理博客3?上課講的敲一遍轉(zhuǎn)載于:https://blog.51cto.com/silencezone/2361369
總結(jié)
以上是生活随笔為你收集整理的九、多表模型创建,一对一,一对多,基于对像的多表模型等的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js异步问题
- 下一篇: OAuth2简易实战(四)-Github