1. 程式人生 > 實用技巧 >Django基礎五之django模型層(二)多表操作

Django基礎五之django模型層(二)多表操作

三種關係:一對一,一對多,多對多

建立表

一對一
    xx = models.OneToOneField(to='表名',to_field='欄位名',on_delete=models.CASCADE)  #刪除時的一些級聯效果,to_field可以不寫,預設是關聯到另一張表的主鍵,on_delete在1.x版本的django中不用寫,預設是級聯刪除的,2.x版本的django要寫.
    
一對多
    xx = models.ForeignKey(to='表名',to_field='欄位名',on_delete=models.CASCADE)
多對多
    xx = models.ManyToManyField(to='
另外一個表名') #這是自動建立第三表 示例 from django.db import models # Create your models here. from django.db import models # Create your models here. #作者表 class Author(models.Model): #比較常用的資訊放到這個表裡面 name=models.CharField( max_length=32) age=models.IntegerField() # authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)
authorDetail=models.OneToOneField(to='AuthorDetail') #一對一到AuthorDetail表 生成為表字段之後,會自動變為authorDetail_id這樣有一個名稱 # 外來鍵欄位 -- 外來鍵欄位名_id # foreign+unique def __str__(self): return self.name #作者詳細資訊表 class AuthorDetail(models.Model): birthday=models.DateField() # telephone=models.BigIntegerField()
telephone=models.CharField(max_length=32) 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() #charfield -- asdfasdf def __str__(self): return self.name #書籍表 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) #decimal(16,2) publishs=models.ForeignKey(to="Publish") authors=models.ManyToManyField(to='Author',) def __str__(self): return self.title #手動建立第三張表,暫時忽略 # class BookToAuthor(models.Model): # book_id = models.ForeignKey(to='Book') # author_id = models.ForeignKey(to='Author') # # xx = models.CharField(max_length=12)

增刪改查

#1 增
    #1.1 一對一增加
    # new_author_detail = models.AuthorDetail.objects.create(
    #     birthday='1979-08-08',
    #     telephone='138383838',
    #     addr='黑龍江哈爾濱'
    # )
    # obj = models.AuthorDetail.objects.filter(addr='山西臨汾').first()

    #方式1
    # models.Author.objects.create(
    #     name='王濤',
    #     age='40',
    #     authorDetail=new_author_detail,
    # )
    # 方式2  常用
    # models.Author.objects.create(
    #     name='王濤',
    #     age='40',
    #     authorDetail_id=obj.id,
    # )

    # 一對多
    #方式1
    # obj = models.Publish.objects.get(id=2)
    # models.Book.objects.create(
    #     title = '李帥的床頭故事',
    #     publishDate='2019-07-22',
    #     price=3,
    #     # publishs=models.Publish.objects.get(id=1),
    #     publishs=obj,
    #
    # )
    # 方式2 常用
    # models.Book.objects.create(
    #     title='李帥的床頭故事2',
    #     publishDate='2019-07-21',
    #     price=3.5,
    #     # publishs=models.Publish.objects.get(id=1),
    #     publishs_id=obj.id
    #
    # )

    # 多對多
    # 方式1   常用
    # book_obj = models.Book.objects.get(nid=1)
    # book_obj.authors.add(*[1,2])
    # 方式2
    # author1 = models.Author.objects.get(id=1)
    # author2 = models.Author.objects.get(id=3)
    # book_obj = models.Book.objects.get(nid=5)
    # book_obj.authors.add(*[author1,author2])

一對一和一對多的刪除和單表刪除是一樣的
# 一對一  表一外來鍵關聯到表二,表一刪除,不影響表2,表2刪除會影響表1
    # models.AuthorDetail.objects.get(id=2).delete()
    # models.Author.objects.get(id=3).delete()

    # 一對多
    # models.Publish.objects.get(id=1).delete()
    # models.Book.objects.get(nid=1).delete()

    # 多對多關係刪除
    # book_obj = models.Book.objects.get(nid=6)
    # book_obj.authors.remove(6)
    # book_obj.authors.remove(*[5,6])
    # book_obj.authors.clear()
    # book_obj.authors.add(*[1,])
    # book_obj.authors.set('1')
    # book_obj.authors.set(['5','6']) #刪除然後更新

更新

  # 更新
    # 一對一
    # models.Author.objects.filter(id=5).update(
    #     name='崔老師',
    #     age=16,
    #     # authorDetail=models.AuthorDetail.objects.get(id=5),
    #     authorDetail_id=4,
    # )
    #一對多
    # models.Book.objects.filter(pk=4).update(
    #     title='B哥的往事2',
    #     # publishs=models.Publish.objects.get(id=3),
    #     publishs_id=3,
    # )
    
    #一對多
    models.Publish.objects.filter(pk=2).update(
        id=4, # 沒有級聯更新,報錯!!
    )

基於物件的跨表查詢 -- 類似於子查詢

正向查詢和反向查詢

關係屬性(欄位)寫在哪個類(表)裡面,從當前類(表)的資料去查詢它關聯類(表)的資料叫做正向查詢,反之叫做反向查詢

#查詢
    # 一對一
        # 正向查詢
        #1 查詢崔老師的電話號
    # author_obj = models.Author.objects.filter(name='崔老師').first()
    # # print(author_obj.authorDetail) #遼寧峨眉山
    # # print(author_obj.authorDetail.telephone) #444
    #     #2 反向查詢
    #     #2 查詢一下這個444電話號是誰的.
    # author_detail_obj = models.AuthorDetail.objects.get(telephone='444')
    # print(author_detail_obj.author) #崔老師
    # print(author_detail_obj.author.name) #崔老師


    '''        正向查詢:Authorobj.authorDetail,物件.關聯屬性名稱
        Author----------------------------------->AuthorDetail
              <-----------------------------------
              反向查詢:AuthorDetailobj.author  ,物件.小寫類名
    '''

    # 一對多
    # 查詢一下李帥的床頭故事這本書的出版社是哪個
    # 正向查詢
    book_obj = models.Book.objects.get(title='李帥的床頭故事')
    print(book_obj.publishs) #B哥出版社
    print(book_obj.publishs.name) #B哥出版社

    # B哥出版社出版社出版了哪些書
    # 反向查詢
    pub_obj = models.Publish.objects.get(name='B哥出版社')
    print(pub_obj.book_set.all()) #<QuerySet [<Book: 李帥的床頭故事>, <Book: 李帥的床頭故事2>]>

    '''   正向查詢 book_obj.publishs  物件.屬性
    Book ---------------------------------------------> Publish
        <----------------------------------------------
          反向查詢 publish_obj.book_set.all()  物件.表名小寫_set
    '''

    # 多對多
    # 李帥的床頭故事這本書是誰寫的
    # 正向查詢
    book_obj = models.Book.objects.get(title='李帥的床頭故事')
    print(book_obj.authors.all())
    # 高傑寫了哪些書
    author_obj = models.Author.objects.get(name='高傑')
    print(author_obj.book_set.all())

    '''       正向查詢 book_obj.authors.all()  物件.屬性
        Book ---------------------------------------------> Author
            <----------------------------------------------
              反向查詢 author_obj.book_set.all()  物件.表名小寫_set
    '''

基於雙下劃綫的跨表查詢 -- 連表 join

正向查詢和反向查詢

#查詢
    # 一對一
    # 1. 查詢崔老師的電話號
    # 方式1  正向查詢
    # obj = models.Author.objects.filter(name='崔老師').values('authorDetail__telephone')
    # print(obj) #<QuerySet [{'authorDetail__telephone': '444'}]>
    # 方式2  反向查詢
    # obj = models.AuthorDetail.objects.filter(author__name='崔老師').values('telephone','author__age')
    # print(obj) #<QuerySet [{'telephone': '444'}]>
    # 2. 哪個老師的電話是444
    # 正向
    # obj = models.Author.objects.filter(authorDetail__telephone='444').values('name')
    # print(obj)
    # 反向
    # obj = models.AuthorDetail.objects.filter(telephone='444').values('author__name')
    # print(obj)

    # 一對多
    # 查詢一下李帥的床頭故事這本書的出版社是哪個
    # obj = models.Book.objects.filter(title='李帥的床頭故事').values('publishs__name')
    # print(obj) #<QuerySet [{'publishs__name': 'B哥出版社'}]>

    # obj = models.Publish.objects.filter(book__title='李帥的床頭故事').values('name')
    # obj = models.Publish.objects.filter(xx__title='李帥的床頭故事').values('name')
    # print(obj)

    # B哥出版社出版社出版了哪些書
    # obj = models.Publish.objects.filter(name='B哥出版社').values('book__title')
    # print(obj) #<QuerySet [{'book__title': '李帥的床頭故事'}, {'book__title': '李帥的床頭故事2'}]>

    # obj = models.Book.objects.filter(publishs__name='B哥出版社').values('title')
    # print(obj) #<QuerySet [{'title': '李帥的床頭故事'}, {'title': '李帥的床頭故事2'}]>

    # 李帥的床頭故事這本書是誰寫的
    # obj = models.Book.objects.filter(title='李帥的床頭故事').values('authors__name')
    # print(obj)
    # obj = models.Author.objects.filter(book__title='李帥的床頭故事').values('name')
    # print(obj) #<QuerySet [{'name': '高傑'}, {'name': '崔老師'}]>

    #高傑寫了哪些書
    # obj = models.Book.objects.filter(authors__name='高傑').values('title')
    # print(obj)
    # obj = models.Author.objects.filter(name='高傑').values('book__title')
    # print(obj)

    #進階的
    # B哥出版社 出版的書的名稱以及作者的名字
    # obj = models.Book.objects.filter(publishs__name='B哥出版社').values('title','authors__name')
    # print(obj)
    #<QuerySet [{'title': '李帥的床頭故事', 'authors__name': '高傑'}, {'title': '李帥的床頭故事', 'authors__name': '崔老師'}, {'title': '李帥的床頭故事2', 'authors__name': '崔老師'}, 
{'title': '李帥的床頭故事2', 'authors__name': '王濤'}]>
''' SELECT app01_book.title,app01_author.name from app01_publish INNER JOIN app01_book on app01_publish.id=app01_book.publishs_id INNER JOIN app01_book_authors on app01_book.nid = app01_book_authors.book_id INNER JOIN app01_author ON app01_author.id = app01_book_authors.author_id where app01_publish.name='B哥出版社'; :param request: :return: ''' # obj = models.Publish.objects.filter(name='B哥出版社').values('book__title','book__authors__name') # print(obj) # obj = models.Author.objects.filter(book__publishs__name='B哥出版社').values('name','book__title') # print(obj) # authorDetail author book publish # 手機號以4開頭的作者出版過的所有書籍名稱以及出版社名稱 # ret = models.AuthorDetail.objects.filter(telephone__startswith='4').values('author__book__title','author__book__publishs__name') # print(ret) #QuerySet [{'author__book__title': '李帥的床頭故事', 'author__book__publishs__name': 'B哥出版社'}, {'author__book__title': '李帥的床頭故事2', 'author__book__publishs__name': 'B哥出版社'}]> #查詢一下B哥出版社出版了哪些書 # obj = models.Publish.objects.filter(name='B哥出版社').first() # print(obj.xx.all())

聚合

    from django.db.models import Avg,Max,Min,Sum,Count

    # 計算所有圖書的平均價格
    # obj = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price')) #aggregate()是QuerySet 的一個終止子句,得到的是個字典.
    # print(obj['m'] - 2) #{'price__avg': 2.833333}

分組

annotate

# models.Publish.objects.annotate(a=Avg('book__price')).values('a')

# models.Book.objects.values('publish_id','id').annotate(a=Avg('price')) {'pulish_id':1,'a':11.11}

F查詢和Q查詢

from django.db.models import F,Q

F  針對自己單表中欄位的比較和處理
models.Book.objects.filter(good__gt=F('comment')*2)
models.Book.objects.all().update(price=F('price')+1)

Q    &  |  非~
filter(Q(xx=11)|Q(ss=22)&Q(oo=33))
filter(Q(Q(xx=11)|Q(ss=22))&Q(oo=33))  &優先順序高
filter(Q(Q(xx=11)|Q(ss=22))&Q(oo=33),name='dd')  

執行原生sql(瞭解)

models.Publish.objects.raw('原生sql')

from django.db import connection
cursor = connection.cursor()
cursor.excute(sql,[1,])
cursor.fetchall()

展示sql的

models.Book.objects.filter(good__gt=F('comment')*2)
from django.db import connection
print(connection.queries)