1. 程式人生 > >Django--ORM多表操作

Django--ORM多表操作

一 建立表模型

假設:

  作者模型:一個作者有姓名和年齡。

  作者詳細模型:把作者的詳情放到詳情表,包含生日,手機號,家庭住址等資訊。作者詳情模型和作者模型之間是一對一的關係(one-to-one)

  出版商模型:出版商有名稱,所在城市以及email。

  書籍模型: 書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關係就是多對多的關聯關係(many-to-                            many);一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關係(one-to-many)。

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=32)
    email = models.EmailField()


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name 
= models.CharField(max_length=32) sex = models.IntegerField() authordetail = models.OneToOneField(to='AuthorDetail', to_field='id') class 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) 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.name

二 增刪改查

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day77.settings")
    import django

    django.setup()

    from app01.models import *

    # 一對多新增資料
    # 新增一本北京出版社出版的書
    # 第一種方式
    # ret=Book.objects.create(name='紅樓夢',price=34.5,publish_id=1)
    # print(ret.name)
# 第二種方式,存物件publish=出版社的物件,存到資料庫,是一個id # publish=Publish.objects.get(id=1) # pk是主鍵,通過主鍵查詢 # publish=Publish.objects.get(pk=1) # publish = Publish.objects.filter(pk=2).first() # ret = Book.objects.create(name='西遊記', price=34.5, publish=publish) # print(ret.name)

# 一對多修改資料 # book=Book.objects.get(pk=1) # # book.publish=出版社物件 # book.publish_id=2 # book.save()
# 方式二 # book=Book.objects.filter(pk=1).update(publish=出版社物件) # book=Book.objects.filter(pk=1).update(publish_id=1)

# 多對多新增 # 為紅樓夢這本書新增一個叫lqz,egon的作者 # lqz=Author.objects.filter(name='lqz').first() # egon=Author.objects.filter(name='egon').first() # book=Book.objects.filter(name='紅樓夢').first() # # add 新增多個物件 # book.authors.add(lqz,egon) # add新增作者id # book.authors.add(1,2)

#刪除 remove,可以傳物件,可以傳id,可以傳多個,不要混著用 # book.authors.remove(lqz) # book.authors.remove(2) # book.authors.remove(1,2)

# clear清空所有 # book.authors.clear() # set,先清空,在新增,要傳一個列表,列表內可以是, id,也可以是物件 # book.authors.set([lqz,]) # ********這樣不行,因為它打散了傳過去了,相當於book.authors.set(lqz) # book.authors.set(*[lqz,])

三 基於物件的跨表查詢

 '''
    一對一
    正向   author---關聯欄位在author--->authordetail   ------>  按欄位
    反向   authordetail------關聯欄位在author--->author  -----> 按表名小寫
    
    '''
    # 查詢lqz作者的手機號   正向查詢
    # author=Author.objects.filter(name='lqz').first()
    # # author.authordetail 就是作者詳情的物件
    # authordetail=author.authordetail
    # print(authordetail.phone)
   # 查詢地址是 :山東 的作者名字   反向查詢
   # authordetail=AuthorDetail.objects.filter(addr='山東').first()
   # # authordetail.author  這是作者物件
   # author=authordetail.author
   # print(author.name)

    #一對多
    '''
    一對多
    正向   book---關聯欄位在book--->publish   ------>  按欄位
    反向   publish------關聯欄位在book--->book  -----> 按表名小寫_set.all()
    '''
    # 正向 查詢紅樓夢這本書的出版社郵箱
    # book=Book.objects.filter(name='紅樓夢').first()
    # # book.publish  就是出版社物件
    # pulish=book.publish
    # print(pulish.email)
    # 反向  查詢地址是北京 的出版社出版的圖書
    # publish=Publish.objects.filter(addr='北京').first()
    # # publish.book_set.all()  拿出所有的圖書
    # books=publish.book_set.all()
    # # 統計一下條數
    # books=publish.book_set.all().count()
    # print(books)

    '''
    多對多
    正向   book---關聯欄位在book--->author   ------>  按欄位.all()
    反向   author------關聯欄位在book--->book  -----> 按表名小寫_set.all()
    '''
    #查詢紅樓夢這本書所有的作者
    # book=Book.objects.filter(name='紅樓夢').first()
    # book.authors.all()  #是所有的作者,是一個queryset物件,可以繼續點
    # print(book.authors.all())

    # 查詢lqz寫的所有書
    # lqz=Author.objects.filter(name='lqz').first()
    # books=lqz.book_set.all()
    # print(books)

    # 連續跨表
    # 查詢紅樓夢這本書所有的作者的手機號
    # book=Book.objects.filter(name='紅樓夢').first()
    # authors=book.authors.all()
    # for author in authors:
    #     authordetail=author.authordetail
    #     print(authordetail.phone)
  基於物件的查詢---是子查詢也就是多次查詢

四 基於雙下劃線的查詢

 # 一對一
    # 查詢lqz作者的手機號   正向查詢  跨表的話,按欄位
    # 以author表作為基表
    # ret=Author.objects.filter(name='lqz').values('authordetail__phone')
    # print(ret)
# 以authordetail作為基表 反向查詢,按表名小寫 跨表的話,用表名小寫 # ret=AuthorDetail.objects.filter(author__name='lqz').values('phone') # print(ret)
# 查詢lqz這個作者的性別和手機號 # 正向 # ret=Author.objects.filter(name='lqz').values('sex','authordetail__phone') # print(ret) # 查詢手機號是13888888的作者性別 # ret=Author.objects.filter(authordetail__phone='13888888').values('sex') # print(ret) # ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex') # print(ret) # 基於雙 下劃線的一對多查詢 # 查詢出版社為北京出版社出版的所有圖書的名字,價格 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price') # print(ret) # ret=Book.objects.filter(publish__name='北京出版社').values('name','price') # print(ret) # 查詢北京出版社出版的價格大於19的書 # ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name','book__price') # print(ret)
# 多對多 # 查詢紅樓夢的所有作者名字 # ret=Book.objects.filter(name='紅樓夢').values('authors__name') # print(ret) # ret=Author.objects.filter(book__name='紅樓夢').values('name') # print(ret) # 查詢圖書價格大於30的所有作者名字 # ret=Book.objects.filter(price__gt=30).values('authors__name') # print(ret)
# 進階練習--連續跨表 # 查詢北京出版社出版過的所有書籍的名字以及作者的姓名 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name') # print(ret) # ret=Book.objects.filter(publish__name='北京出版社').values('name','authors__name') # print(ret) # 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱 # ret=AuthorDetail.objects.filter(phone__startswith='13').values('author__book__name','author__book__publish__name') # print(ret) # ret=Book.objects.filter(authors__authordetail__phone__startswith='13').values('name','publish__name') # print(ret)

五 聚合查詢和分組查詢

from django.db.models import Avg,Count,Max,Min,Sum
  
#聚合查詢aggregate() # 計算所有圖書的平均價格 # ret=Book.objects.all().aggregate(Avg('price')) # print(ret)
# 計算圖書的最高價格 # ret=Book.objects.all().aggregate(Max('price')) # print(ret)
#aggregate是queryset的終止子句
# 計算圖書的最高價格,最低價格,平均價格,總價 # ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price')) # print(ret) #分組查詢annotate() # 統計每一本書作者個數 # ret=Book.objects.all().annotate(c=Count('authors')) # print(ret) # for r in ret: # print(r.name,'---->',r.c) # ret=Book.objects.all().annotate(c=Count('authors')).values('name','c') # print(ret)
# 統計每一個出版社的最便宜的書(以誰group by 就以誰為基表) # ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m') # print(ret)
# 統計每一本以py開頭的書籍的作者個數 # ret1=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret1)
# 總結: group by 誰,就以誰做基表,filter過濾,annotate取分組,values取值
# 總結終極版本 # values在前,表示group by 在後,表示取值 # filter在前,表示where條件,在後表示having
# 統計每一本以py開頭的書籍的作者個數--套用模板 # ret2=Book.objects.all().values('name').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret2)
# 查詢各個作者出的書的總價格 # ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s') # ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s') # print(ret)
#查詢名字叫lqz作者書的總價格 # ret=Author.objects.all().values('pk').filter(name='lqz').annotate(s=Sum('book__price')).values('name','s') # print(ret)
# 查詢所有作者寫的書的總價格大於30 # ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s') # ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=30).values('name','s') # print(ret)
# 總結終極版本 # values在前,表示group by 在後,表示取值 # filter在前,表示where條件,在後表示having
# 統計不止一個作者的圖書 ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c') # ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num') print(ret)

六 F查詢和Q查詢

   
   # F函式
   from
django.db.models import F # 查詢評論數大於閱讀數的書 # 這樣不行,進行不下去了 # ret=Book.objects.all().filter(commit_num__gt=reat_num) # 這麼來做 # ret=Book.objects.all().filter(commit_num__gt=F('reat_num')) # print(ret) # 把所有書的評論數加1 # 不行,進行不下去 # ret=Book.objects.all().update(commit_num+=1) # 不行,進行不下去 # ret=Book.objects.all().update(commit_num=commit_num+1) # 這樣來做 # ret=Book.objects.all().update(commit_num=F('commit_num')+1) # print(ret) # 把python這本書的閱讀數減5 # ret = Book.objects.all().filter(name='python').update(reat_num=F('reat_num') - 5) # print(ret) # Q函式 為了表示與& ,或 | ,非 ~, from django.db.models import Q
# 查詢作者名字是lqz或者名字是egon的書 # 這樣行不通 # ret=Book.objects.all().filter(authors__name='lqz',authors__name='egon') # 這樣出來 # ret=Book.objects.all().filter(Q(authors__name='lqz')|Q(authors__name='egon')) # print(ret) # 沒有意義 # ret = Book.objects.all().filter(Q(authors__name='lqz') & Q(authors__name='egon')) # print(ret)
# 查詢作者不是lqz的書 # ret=Book.objects.filter(~Q(authors__name='lqz')) # print(ret)    # 構建很複雜的邏輯,需要用括號來區分    # ret = Book.objects.filter((Q(name='紅樓夢') & Q(price__gt=100)) | Q(pk__gt=2))    # print(ret)