多表操作——增刪改查
阿新 • • 發佈:2019-01-14
關聯欄位與外來鍵約束沒有必然的聯絡(建管理欄位是為了進行查詢,建約束是為了不出現髒資料)
class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField() # 閱讀數 # reat_num=models.IntegerField(default=0)View Code# 評論數 # commit_num=models.IntegerField(default=0) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) authors=models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name= models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE) class AuthorDatail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday= models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField()
- 對於外來鍵欄位,Django 會在欄位名上新增"_id" 來建立資料庫中的列名
- 外來鍵欄位 ForeignKey 有一個 null=True 的設定(它允許外來鍵接受空值 NULL),你可以賦給它空值 None 。
新增表記錄
# -----一對多新增 pub=Publish.objects.create(name='egon出版社',email='[email protected]',city='山東') print(pub) # 為book表繫結和publish的關係 import datetime,time now=datetime.datetime.now().__str__() now = datetime.datetime.now().strftime('%Y-%m-%d') print(type(now)) print(now) # 日期型別必須是日期物件或者字串形式的2018-09-12(2018-9-12),其它形式不行 Book.objects.create(name='海燕3',price=333.123,publish_date=now,publish_id=2) Book.objects.create(name='海3燕3',price=35.123,publish_date='2018/02/28',publish=pub) pub=Publish.objects.filter(nid=1).first() book=Book.objects.create(name='測試書籍',price=33,publish_date='2018-7-28',publish=pub) print(book.publish.name) # 查詢出版了紅樓夢這本書出版社的郵箱 book=Book.objects.filter(name='紅樓夢').first() print(book.publish.email)
一對多新增新增記錄 # 當前生成的書籍物件 book_obj=Book.objects.create(title="追風箏的 人",price=200,publishDate="2012-11-12",publish_id=1) # 為書籍繫結的做作者物件 yuan=Author.objects.filter(name="yuan").first() # 在Author表中主鍵為2的紀錄 egon=Author.objects.filter(name="alex").first() # 在Author表中主鍵為1的紀錄 # 繫結多對多關係,即向關係表book_authors中新增紀錄 book_obj.authors.add(yuan,egon) # 將某些特定的 model 物件新增到被關聯物件集合中。 ======= book_obj.authors.add(*[]) book = Book.objects.filter(name='紅樓夢').first() egon=Author.objects.filter(name='egon').first() lqz=Author.objects.filter(name='lqz').first() # 1 沒有返回值,直接傳物件 book.authors.add(lqz,egon) # 2 直接傳作者id book.authors.add(1,3) # 3 直接傳列表,會打散 book.authors.add(*[1,2]) # 解除多對多關係 book = Book.objects.filter(name='紅樓夢').first() # 1 傳作者id book.authors.remove(1) # 2 傳作者物件 egon = Author.objects.filter(name='egon').first() book.authors.remove(egon) #3 傳*列表 book.authors.remove(*[1,2]) #4 刪除所有 book.authors.clear() # 5 拿到與 這本書關聯的所有作者,結果是queryset物件,作者列表 ret=book.authors.all() # print(ret) # 6 queryset物件,又可以繼續點(查詢紅樓夢這本書所有作者的名字) ret=book.authors.all().values('name') print(ret) # 以上總結: # (1) # book=Book.objects.filter(name='紅樓夢').first() # print(book) # 在點publish的時候,其實就是拿著publish_id又去app01_publish這個表裡查資料了 # print(book.publish) # (2)book.authors.all()
多對多關係其它常用API:
book_obj.authors.remove() # 將某個特定的物件從被關聯物件集合中去除。 ====== book_obj.authors.remove(*[]) book_obj.authors.clear() #清空被關聯物件集合 book_obj.authors.set() #先清空再設定
查詢:
- 不變的規則:
- -正向查詢按欄位
-反向查詢按表名小寫
- -正向查詢按欄位
- 不變的規則:
-
(正向:關聯關係所在表————>查詢表)
-
(反向:查詢表---->關係關係所在表)
-
基於物件的跨表查詢(多次查詢)
一對一:
-正向查詢按欄位
-反向查詢按表名小寫
一對多:
-正向查詢按欄位(正向查詢一定會查出一個來)
#基於name拿到物件再去關聯表author_detail中按欄位addr拿到欄位值
-反向查詢按 表名 小寫 "_set ".all()(返回結果是queryset物件)
多對多:
-正向查詢按欄位.all()(正向查詢一定會查出多個來)
-反向查詢按表名小寫_set.all()(返回結果是queryset物件)
基於雙下劃線的跨表查詢 ps:"__"表示連表
-在filter和values中都可以做連表操作(也就是都可以寫 __)
關於效率:無論以誰做基表,沒有效率之分(本質都是在一個關係表(外來鍵約束)中查詢)
基於物件的跨表查詢
一對多查詢(publish與book):
正向查詢(按欄位:publish) # 查詢主鍵為1的書籍的出版社所在的城市 book_obj=Book.objects.filter(pk=1).first() # book_obj.publish 是主鍵為1的書籍物件關聯的出版社物件 print(book_obj.publish.city) 反向查詢(按表名:book_set) publish=Publish.objects.get(name="蘋果出版社") #publish.book_set.all() : 與蘋果出版社關聯的所有書籍物件集合 book_list=publish.book_set.all() for book_obj in book_list: print(book_obj.title)
# 一對多正向查詢 book=Book.objects.filter(name='紅樓夢').first() print(book.publish)#與這本書關聯的出版社物件 print(book.publish.name) # 一對多反向查詢 # 人民出版社出版過的書籍名稱 pub=Publish.objects.filter(name='人民出版社').first() ret=pub.book_set.all() print(ret)View Code
一對一查詢(Author 與 AuthorDetail):
正向查詢(按欄位:authorDetail):
egon=Author.objects.filter(name="egon").first() print(egon.authorDetail.telephone)
反向查詢(按表名:author):
# 查詢所有住址在北京的作者的姓名 authorDetail_list=AuthorDetail.objects.filter(addr="beijing") for obj in authorDetail_list: print(obj.author.name)
# 一對一正向查詢 # lqz的手機號 lqz=Author.objects.filter(name='lqz').first() tel=lqz.author_detail.telephone print(tel) # 一對一反向查詢 # 地址在北京的作者姓名 author_detail=AuthorDatail.objects.filter(addr='北京').first() name=author_detail.author.name print(name)View Code
多對多查詢 (Author 與 Book):
正向查詢(按欄位:authors):
# 眉所有作者的名字以及手機號 book_obj=Book.objects.filter(title="眉").first() authors=book_obj.authors.all() for author_obj in authors: print(author_obj.name,author_obj.authorDetail.telephone)
反向查詢(按表名:book_set):
# 查詢egon出過的所有書籍的名字 author_obj=Author.objects.get(name="egon") book_list=author_obj.book_set.all() #與egon作者相關的所有書籍 for book_obj in book_list: print(book_obj.title)
# 正向查詢----查詢紅樓夢所有作者名稱 book=Book.objects.filter(name='紅樓夢').first() ret=book.authors.all() print(ret) for auth in ret: print(auth.name) # 反向查詢 查詢lqz這個作者寫的所有書 author=Author.objects.filter(name='lqz').first() ret=author.book_set.all() print(ret)View Code
注意:
你可以通過在 ForeignKey() 和ManyToManyField的定義中設定 related_name 的值來覆寫 FOO_set 的名稱。例如,如果 Article model 中做一下更改:
publish = ForeignKey(Book, related_name='bookList')
那麼接下來就會如我們看到這般:
# 查詢 人民出版社出版過的所有書籍 publish=Publish.objects.get(name="人民出版社") book_list=publish.bookList.all() # 與人民出版社關聯的所有書籍物件集合
基於雙下劃線的跨表查詢
一對多查詢: # 練習: 查詢蘋果出版社出版過的所有書籍的名字與價格(一對多) # 正向查詢 按欄位:publish queryResult=Book.objects .filter(publish__name="蘋果出版社") .values_list("title","price") # 反向查詢 按表名:book queryResult=Publish.objects .filter(name="蘋果出版社") .values_list("book__title","book__price") 查詢的本質一樣,就是select from的表不一樣 # 正向查詢按欄位,反向查詢按表名小寫 # 查詢紅樓夢這本書出版社的名字 # select * from app01_book inner join app01_publish # on app01_book.publish_id=app01_publish.nid ret=Book.objects.filter(name='紅樓夢').values('publish__name') print(ret) ret=Publish.objects.filter(book__name='紅樓夢').values('name') print(ret)一對多
# 練習: 查詢alex出過的所有書籍的名字(多對多) # 正向查詢 按欄位:authors: queryResult=Book.objects .filter(authors__name="yuan") .values_list("title") # 反向查詢 按表名:book queryResult=Author.objects .filter(name="yuan") .values_list("book__title","book__price") # 正向查詢按欄位,反向查詢按表名小寫 # 查詢紅樓夢這本書出版社的名字 # select * from app01_book inner join app01_publish # on app01_book.publish_id=app01_publish.nid ret=Book.objects.filter(name='紅樓夢').values('publish__name') print(ret) ret=Publish.objects.filter(book__name='紅樓夢').values('name') print(ret) # sql 語句就是from的表不一樣 # -------多對多正向查詢 # 查詢紅樓夢所有的作者 ret=Book.objects.filter(name='紅樓夢').values('authors__name') print(ret) # ---多對多反向查詢 ret=Author.objects.filter(book__name='紅樓夢').values('name') ret=Author.objects.filter(book__name='紅樓夢').values('name','author_detail__addr') print(ret)多對多查詢
# 練習: 查詢人民出版社出版過的所有書籍的名字以及作者的姓名 # 正向查詢 queryResult=Book.objects .filter(publish__name="人民出版社") .values_list("title","authors__name") # 反向查詢 queryResult=Publish.objects .filter(name="人民出版社") .values_list("book__title","book__authors__age","book__authors__name") # 練習: 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱 # 方式1: queryResult=Book.objects .filter(authors__authorDetail__telephone__regex="151") .values_list("title","publish__name") # 方式2: ret=Author.objects .filter(authordetail__telephone__startswith="151") .values("book__title","book__publish__name")進階練習(連續跨表) 另外:https://www.cnblogs.com/liuqingzheng/articles/9499252.html