表和表之間的關係java
一對1、多對1、多對多python
# 做者表 比較經常使用的信息放在這個表中 class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() authorDetail=models.OneToOneField(to='AuthorDetail') #與AuthorDetail創建一對一的關係,一對一的這個關係字段寫在這兩個表的任意一個表裏面均可以,models.OneToOneField(to='AuthorDetail')就是foreignkey+unique,只不過不須要咱們本身來寫參數了,而且orm會自動幫你給這個字段名字拼上一個_id,數據庫中字段名稱爲authorDetail_id也能夠寫成這樣# authorDetail = models.OneToOneField(to="AuthorDetail", to_field="id",on_delete=models.CASCADE) on_delete=models.CASCADE級聯關係 def __str__(self): return self.name # 做者信息表 不經常使用的做者信息放這個表中 class AuthorDetail(models.Model): brithday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField(max_length=64) def __str__(self): return self.addr # 書籍出版社表 class Publish(models.Model): name=models.CharField(max_length=32) city=models.CharField(max_length=32) email=models.EmailField() def __str__(self): return self.name # 書籍表 class Book(models.Model): title=models.CharField(max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_palces=2) # 與Publish創建一對多的關係,外鍵字段創建在多的一方,字段publish若是是外鍵字段,那麼它自動是int類型 # foreignkey裏面能夠加不少的參數,都是須要我們學習的,慢慢來,to指向表,to_field指向你關聯的字段,不寫這個,默認會自動關聯主鍵字段,on_delete級聯刪除字段名稱不須要寫成publish_id,orm在翻譯foreignkey的時候會自動給你這個字段拼上一個_id,這個字段名稱在數據庫裏面就自動變成了publish_id publish=models.Foreignkey(to='publish') # 與Author表創建多對多的關係,ManyToManyField能夠建在兩個模型中的任意一個,自動建立第三張表,而且注意一點,你查看book表的時候,你看不到這個字段,由於這個字段就是建立第三張表的意思,不是建立字段的意思,因此只能說這個book類裏面有authors這個字段屬性 authors=models.ManyToManyField(to='Author') def __str__(self): return self.title # 多對多的表關係,咱們學mysql的時候是怎麼創建的,是否是手動建立一個第三張表,而後寫上兩個字段,每一個字段外鍵關聯到另外兩張多對多關係的表,orm的manytomany自動幫咱們建立第三張表,兩種方式創建關係均可以,之後的學習咱們暫時用orm自動建立的第三張表,由於手動建立的第三張表咱們進行orm操做的時候,不少關於多對多關係的表之間的orm語句方法沒法使用 # 若是你想刪除某張表,你只須要將這個表註銷掉,而後執行那兩個數據庫同步指令就能夠了,自動就刪除了。 #注意不論是一對多仍是多對多,寫to這個參數的時候,最後後面的值是個字符串,否則你就須要將你要關聯的那個表放到這個表的上面
操做前先簡單的錄入一些數據:仍是create和save兩個方法,和單表的區別就是看看怎麼添加關聯字段的數據mysql
一對一 方式一: new_author_detail=models.AuthorDetail.objects.create( birthday='1965-10-10', telephone='18335267641', addr='山西大同' ) models.Author.objects.create( name='ll', age='53', authorDetail=new_author_detail, ) 方式二 經常使用 obj=models.AuthorDetail.objects.filter(addr='山西大同').last() print(obj.id) models.Author.objects.create( name='mx', age='52', authorDetail_id=obj.id ) 一對多 obj=models.Publish.objects.get(id=3) models.Book.objects.create( title='故事會新編', publishDate='2019-9-10', price=30, # 方式一 publish=obj # 方式二 經常使用 publish_id=obj.id ) 多對多 方式一 經常使用 book_obj=models.Book.objects.get(id=1) book_obj.authors.add(*[1,2]) #打散 方式二 author1=models.Author.objects.get(id=3) author2=models.Author.objects.get(id=4) book_obj=models.Book.objects.get(id=4) book_obj.authors.add(*[author1,author2])
一對一 models.AuthorDetail.objects.get(id=6).delete() models.Author.objects.get(id=5).delete() 一對多 models.Publish.objects.get(id=1).delete() models.Book.objects.get(id=1).delete() 多對多 book_obj = models.Book.objects.get(id=1) book_obj.authors.remove(*[1, 2]) #刪除 book_obj.authors.clear() #清空 book_obj.authors.add(2,) #添加 book_obj.authors.set(['1','2']) #刪除而後更新
一對一 models.Author.objects.filter(id=1).update( name='安文', age=24, 方式一 # authorDetail_id=5, 方式二 authorDetail=models.AuthorDetail.objects.get(id=3) ) 一對多 models.Book.objects.filter(id=4).update( title='java核心', 方式一 publish_id=4, 方式二 publish=models.Publish.objects.get(id=2) ) 多對多 book_obj.authors.set(['1','2']) #刪除而後更新
正向查詢和反向查詢git
| 關係屬性(字段)寫在那個表中,從當前表(類)的數據去查詢它關聯表(類)中的數據叫正向查詢,反之叫反向查詢 |sql
#一對一 正向查詢 # 查詢yage的電話 author_obj=models.Author.objects.filter(name='yage').first() print(author_obj.authorDetail) print(author_obj.authorDetail.telepbone) 反向查詢 # 查詢這個電話 145523669874 是誰的 author_detail_obj=models.AuthorDertail.objects.get(telrphone=145523669872) print(author_detail_obj.author) print(author_detail_obj.author.name) """ 正向查詢Author_obj.authorDateil,對象.關聯屬性 Author------------------------->AuthorDateil Author<-------------------------AuthorDateil 反向查詢:AuthorDateil.author,對象.小寫類名 """ #一對多 正向查詢 # 查詢某本書 java核心 的 出版社是哪一個 book_obj=models.Book.objects.get(title='java核心') print(book_obj.publish) print(book_obj.publish.name) 反向查詢 #清華出版社出版的那些書 pub_pbj=models.Publish.objects.get(name='清華出版社') print(pub_obj.book_set.all()) """ 正向查詢 book_obj.publishs 對象.屬性 Book------------------------------>>>Publish Book<<<------------------------------Publish 反向查詢 pub_obj.book_set.all() 對象.表名小寫_set """ #多對多 正向查詢 # 查詢某本書 java核心 是誰出版的 book_obj=models.Book.objects.get(title='java核心') print(book_obj.authors.all()) 反向查詢 #查詢 yage 寫了哪些書 author_obj=models.Author.object.get(name='yage') print(author_obj.book_set.all()) """ 正向查詢 book_obj.authors.all() 對象.屬性 book --------------->author book <---------------author 反向查詢 author_obj.book_set.all() 對象.表名小寫_set """
Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關聯關係,它能自動確認 SQL JOIN 聯繫。要作跨關係查詢,就使用兩個下劃線來連接模型(model)間關聯字段的名稱,直到最終連接到你想要的model 爲止。數據庫
''' 基於雙下劃線的查詢就一句話:正向查詢按字段,反向查詢按表名小寫用來告訴ORM引擎join哪張表,一對1、一對多、多對多都是一個寫法,注意,咱們寫orm查詢的時候,哪一個表在前哪一個表在後都沒問題,由於走的是join連表操做。 ''' # 一對一 #1. 查詢yage的電話 # 方式一 正向查詢 obj=models.Author.object.filter(name='yage').values('authorDetail__telepbone') print(obj) # 方式二 反向查詢 obj=models.AuthorDetail.objects.filter(author__name='yage').values('telephone') print(obj) #2. 誰的電話是 145523669874 obj=models.AuthorDetail.object.filter(telephon='145523669874').values('authors__name') print(obj) obj=models.Author.objects.filter(authorDetail__telephon='145523669874').values('name') print(obj) # 一對多 # 查詢某本書 java核心 的 出版社是哪一個 obj=models.Book.objects.filter(name='java核心').values('publish__name') obj=models.Publish.objects.filter(book__title='java核心').values('name') # 清華出版社出版的那些書 obj=models.Publish.objects.filter(name='清華出版社').values('book__title') print(obj) obj=models.Book.object.filter(publish__name='清華出版社').values('title') print(obj) # 多對多 # 查詢某本書 java核心 是誰出版的 obj=models.Book.objects.filter(title='java核心').values('authors__name') print(obj) obj=models.Author.objects.filter(book__title='java核心').values('name') print(obj) # 查詢 yage 寫了哪些書 #方法一 obj=models.Author.objects.filter(name='yage').values('book__title') print(obj) #方法二 obj=models.Book.objects.filter(authors__name='yage').values('title') print(obj) #進階查詢一 #清華出版社 出版的書 以及做者姓名 #方法一 obj=models.Publish.objects.filter(name='清華出版社').values('book__title','book__authors__name') print(obj) #方法二 obj=models.Book.objects.filter(publish__name='清華出版社').values('title','authors__name') print(obj) #方法三 obj=models.Author.objects.filter(book__publish__name='清華出版社').values('name','book__title') print(obj) 進階查詢二 #手機號以 14552 開頭的做者 出版過的因此書籍名稱 以及 出版社名稱 #方法一 obj=models.AuthorDetail.objects.filter(telephone__startswith='14552').values('author__book__title' , 'author__book__publish__name') print(obj) #方法二 obj=models.Author.objects.filter(authorDetail__telephone__startswith='14552').values('book__title','book__publish__name') print(obj) #方法三 obj=models.Book.objects.filter(authors__authorDetail__telephone__startswith='14552').values('authors__book__title','authors__book__publish__name') print(obj)
反向查詢時,若是定義了related_name ,則用related_name替換 表名,例如:django
publish = ForeignKey(Book, related_name='bookList')
# 練習: 查詢人民出版社出版過的全部書籍的名字與價格(一對多) # 反向查詢 再也不按表名:book,而是related_name:bookList obj=models.Publish.objects.filter(name="清華出版社").values("bookList__title","bookList__price")
from django.db.models import Avg,Min,Max ,Sum,Count # 計算全部書籍的平均價格 圖書價格的最大值 #aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。 obj=models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price')) print(obj) #{'a': 47.5, 'm': Decimal('78.00')} print(obj['m']-2) #76.00
# 統計每一個出版社出版的書籍的平均價格 ret=models.Book.objects.values('publish_id').annotate(a=Avg('price')) print(ret) #<QuerySet [{'publish_id': 2, 'a': 69.0}, {'publish_id': 3, 'a': 30.0}, {'publish_id': 4, 'a': 22.0}]> ret=models.Publish.objects.annotate(a=Avg('book__price')) print(ret) #<QuerySet [<Publish: 山西出版社>, <Publish: 清華出版社>, <Publish: 江蘇出版社>]> ret = models.Publish.objects.annotate(a=Avg('book__price')).values('name', 'a') print(ret) #<QuerySet [{'name': '山西出版社', 'a': 22.0}, {'name': '清華出版社', 'a': 69.0}, {'name': '江蘇出版社', 'a': 30.0}]>
在上面全部的例子中,咱們構造的過濾器都只是將字段值與某個常量作比較。若是咱們要對兩個字段的值作比較,那該怎麼作呢?咱們在book表裏面加上兩個字段:評論數:comment,收藏數:goodapp
#查詢點贊數大於評論數的書籍 ret=models.Book.objects.filter(good__gt=F('comment')) # 查詢點贊數大於評論數+20的書籍 #Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做。 ret=models.Book.objects.filter(good__gt=F('comment')+20) print(ret) #<QuerySet [<Book: 今天是個好日子>, <Book: java核心>]> #全部書籍的價格+20 models.Book.objects.all().update(price=F('price')+20) #評論數大於100,和 ,點贊數大於100的 ret=models.Book.objects.filter(good__gt=100,comment__gt=100) print(ret) #<QuerySet [<Book: java核心>, <Book: 故事會新編>]>
Q
對象可使用&(與)
、|(或)、~(非)
操做符組合起來。當一個操做符在兩個Q
對象上使用時,它產生一個新的Q
對象。函數
你能夠組合&
和|
操做符以及使用括號進行分組來編寫任意複雜的Q
對象。同時,Q
對象可使用~
操做符取反,這容許組合正常的查詢和取反(NOT
) 查詢:學習
#評論數大於100,或者 點贊數大於100的 ret=models.Book.objects.filter(Q(good__gt=100)|Q(comment__gt=100)) print(ret) #<QuerySet [<Book: java核心>, <Book: 故事會新編>, <Book: LINUX學習>]> #評論數大於100,或者 點贊數小於等於100的 ret = models.Book.objects.filter(~Q(good__gt=100) | Q(comment__gt=100)) print(ret) #評論數大於100,或者 點贊數大於100的 且 price='42' #逗號鏈接的普通查詢條件放在最後 #查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面。例如: ret = models.Book.objects.filter(Q(good__gt=100) | Q(comment__gt=100),price='42') print(ret) #評論數大於100,或者 點贊數大於100的 且 price='42' ret = models.Book.objects.filter(Q(good__gt=100) | Q(comment__gt=100) & Q(price='42')) #&優先級高 ret = models.Book.objects.filter(Q(Q(good__gt=100) | Q(comment__gt=100)) & Q(price='42')) #|優先級高
在模型查詢API不夠用的狀況下,咱們還可使用原始的SQL語句進行查詢。
Django 提供兩種方法使用原始SQL進行查詢:一種是使用raw()方法,進行原始SQL查詢並返回模型實例;另外一種是徹底避開模型層,直接執行自定義的SQL語句。
raw()管理器方法用於原始的SQL查詢,並返回模型的實例:
注意:raw()語法查詢必須包含主鍵。
這個方法執行原始的SQL查詢,並返回一個django.db.models.query.RawQuerySet 實例。 這個RawQuerySet 實例能夠像通常的QuerySet那樣,經過迭代來提供對象實例。
ret=models.Publish.objects.raw('select * from app01_publish;') print(ret) #<RawQuerySet: select * from app01_publish;> for i in ret: print(i.name) # 直接執行自定義SQL # django提供的接口中獲取數據庫鏈接,而後像使用pymysql模塊同樣操做數據庫 from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) ret = cursor.fetchone()
ret=models.Publish.objects.all() print(ret) from django.db.models import connection print(connection.queries)
#1 查詢每一個做者的姓名以及出版的書的最高價格 ret=models.Author.objects.values('name').annotate(max_price=Max('book__price')) print(ret) #注意:values寫在annotate前面是做爲分組依據用的,而且返回給你的值就是這個values裏面的字段(name)和分組統計的結果字段數據(max_price) #ret=models.Author.objects.annotate(max_price=Max('book__price')).values('name','max_price')#這種寫法是按照Author表的id字段進行分組,返回給你的是這個表的全部model對象,這個對象裏面包含着max_price這個屬性,後面寫values方法是獲取的這些對象的屬性的值,固然,能夠加雙下劃線來連表獲取其餘關聯表的數據,可是獲取的其餘關聯表數據是你的這些model對象對應的數據,而關聯獲取的數據可能不是你想要的最大值對應的那些數據 # 2 查詢做者id大於2做者的姓名以及出版的書的最高價格 ret=models.Author.objects.filter(id__gt=2).annotate(max_price=Max('book__price')).values('name','max_price')#記着,這個values取得是前面調用這個方法的表的全部字段值以及max_pirce的值,這也是爲何咱們取關聯數據的時候要加雙劃線的緣由 print(ret) #3 查詢做者id大於2或者做者年齡大於等於20歲的女做者的姓名以及出版的書的最高價格 ret=models.Author.objects.filter(Q(id__gt=2)|Q(age__gte=20),sex='female').annotate(max_price=Max('book__price')).values('name','max_price') #4 查詢每一個做者出版的書的最高價格 的平均值 ret=models.Author.objects.values('id').annotate(max_price=Max('book__price')).aggregate(Avg('max_price')) #{'max_price__avg': 555.0} 注意,aggregate是queryset的終止句,獲得的是字典 ret=models.Author.objects.annotate(max_price=Max('book__price')).aggregate(Avg('max_price')) #{'max_price__avg': 555.0} 注意,aggregate是queryset的終止句,獲得的是字典
app應用中admin.py
from django.contrib import admin from app01 import models # Register your models here. admin.site.register(models.Book) admin.site.register(models.Author) admin.site.register(models.AuthorDetail) admin.site.register(models.Publish)
點擊Tools 中run manage.py task 執行createsuperuser建立一個超級用戶(username和password),而後能夠訪問http://127.0.0.1:8000/admin/ ,能夠直接操做數據庫進行增刪改查。
| 訪問http://127.0.0.1:8000/admin/ |