Django中的多表操作

多表操作是常用的資料庫操作,如果不使用多表操作,建立資料庫是沒有意義的。

多表操作包含三種類型:

  1. 一對多
  2. 多對多
  3. 一對一

每一種類型又包含正向查詢及反向查詢兩個方向。

為了更好的練習多表操作,我們要先創建資料庫表的模型:

 1 #書籍表,與作者建立多對多關係,出版社建立多對一關係
 2 class Book(models.Model):
 3     nid = models.AutoField(primary_key=True)
 4     title = models.CharField(max_length=32)
 5     price = models.DecimalField(max_digits=8,decimal_places=2)
 6     pub_date = models.DateTimeField()
 7     publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) #級聯刪除
 8     authors = models.ManyToManyField(to="Author")
 9     def __str__(self):
10         return self.title
11 
12 #出版社表,與書籍建立一對多關係
13 class Publish(models.Model):
14     nid = models.AutoField(primary_key=True)
15     name = models.CharField(max_length=32)
16     email = models.CharField(max_length=32)
17   
18 #作者表,與書籍建立多對多關係,與作者詳情建立一對一關係
19 class Author(models.Model):
20     nid = models.AutoField(primary_key=True)
21     name = models.CharField(max_length=32)
22     age = models.IntegerField()
23     email = models.CharField(max_length=32)
24     ad = models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE,null=True)
25     # ad = models.ForeignKey("AuthorDetail",on_delete=models.CASCADE,unique=True)
26     def __str__(self):
27         return self.name
28 
29 #作者詳情
30 class AuthorDetail(models.Model):
31     addr = models.CharField(max_length=32)
32     tel=models.IntegerField()
  書籍表 出版社表 作者表 作者詳情
書籍表   多對一 多對多  
出版社表 一對多      
作者表 多對多     一對一
作者詳情     一對一  

使用命令產生資料庫表:

python manage.py makemigrations

python manage.py migrate  

資料庫表格如下:

  • bookstore_author
  • bookstore_authordetail
  • bookstore_book
  • bookstore_book_authors
  • bookstore_publish

與建立單表相同,bookstore為創建的app名稱,下劃線後為表格名稱,django會自動將所有大寫字母轉為小寫字母。

與建立單表不同的:

  1. 在bookstore_book中,有一個字段publish使用 Foreignkey 關聯了出版社的nid,會將表格欄位名稱設為 'fieldname' + '_id' 
  2. bookstore_book_authors為django為多對多關係所自動建立的關係表,表示在book表中與author所建立的關係。

表格建立完成後,我們再新增一些數據:

#使用SQL語法新增數據
#新增出版社
insert into bookstore_publish (name,email) values('蘋果出版社',122);
insert into bookstore_publish (name,email) values('橘子出版社',123);

新增書籍對出版社一對多關聯

#In views.py
#使用django models物件方法來新增
from bookstore import models def addData(request): #建立一對多關聯的方式有兩種 #方法一,直接以id新增: book = models.Book.objects.create( title='python', price=123, pub_date='2019-11-11', publish_id = 1, #使用id新增 ) #方法二,以物件新增: publish_obj = models.Publish.objects.get(name='橘子出版社') #必須先產生出版社物件 #publish_obj = models.Publish.objects.filter(name='橘子出版社').first() book = models.Book.objects.create( title='linux', price=150, pub_date='2019-12-12', publish = publish_ob, #使用物件新增 )

在我們新增書籍對作者的關聯之前,我們的需要先新增一些作者

INSERT INTO bookstore_author (name,age,email) VALUES('Alex',11,111);
INSERT INTO bookstore_author (name,age,email) VALUES('Egon',21,222);
INSERT INTO bookstore_author (name,age,email) VALUES('Jacky',13,333);

再來我們建立一些作者詳情

INSERT INTO bookstore_authordetail (addr,tel) VALUES('台北',111);
INSERT INTO bookstore_authordetail (addr,tel) VALUES('台中',222);
INSERT INTO bookstore_authordetail (addr,tel) VALUES('高雄',333);

作者與作者詳情是有一對一關係的,所以我們讓他們建立起來。一對一也就是 Foreignkey 加上 unique 。

#搜尋相關作者詳情紀錄的物件
alexad = models.AuthorDetail.objects.(tel=111)
egonad = models.AuthorDetail.objects.(tel=222)
jackyad = models.AuthorDetail.objects.(tel=333)

#找出作者的QuerySet
alex = models.Auhtor.objects.filter(name='Alex')
egon = models.Auhtor.objects.filter(name='Egon')
jacky = models.Auhtor.objects.filter(name='Jacky')

#更新作者中的作者詳情
alex.update(ad=alexad)
egon.update(ad=egonad)
jacky.update(ad=jackyad)

有了作者以後,我們就可以開始增加書籍與作者的關係了。

書籍對作者多對多關聯操作,增刪改

#先找出書籍物件
book = models.Book.objects.filter(title='python').first()
jacky = models.Author.objects.filter(name='Jacky').first()
#新增書籍對作者的多對多關聯

#新增一個
book.authors.add(4)
#
book.authors.add(jacky)
#新增多個
book.authors.add(*[1,2,3])
###移除多對多關連### 
#
移除Python這本書對所有authors_id==4的作者
book.authors.remove(4)

#移除Python這本書所有的多對多關連
book.authors.clear()

#更新
book.authors.set([1,2,3])
#等價於
book.authors.clear()
book.authors.add(1,2,3)

表格建立完成以後,我們就可以做一系列的查詢練習了。

基於對象的跨表查詢


一對多
'''
正向查詢 : 關聯屬性所在的表查詢關連表紀錄
反向查詢 :
正向查詢:按字段:book.publish
Book -----------------------------------------------> Publish
         <----------------------------------------------
反向查詢表名小寫_set.all():pub_obj.book_set.all()

'''
1. 查詢python 這本書出版社的名字和郵箱

book = models.Book.objects.filter(title="python").first()
query = book.publishprint(query.name,query.email)

多對多


正向查詢按字段 book.author.all()
Book ------------------------------------------------> Author
         <-----------------------------------------------
反向查詢表名小寫_set.all():alex.book_set.all()

2 蘋果出版社出版的所有書籍的名稱

publish = models.Publish.objects.filter(name="蘋果出版社").first()
query = publish.book_set.all()
print(query)

#3 查詢python書籍作者的年齡
# book = models.Book.objects.filter(title="python").first()
# author = book.authors.all().values("age") #與這本書關聯的作者年齡
# print(author)


#######一對一############

'''
                   正向查詢按字段 alex.ad
Author ------------------------------------------------> AuthorDetail
          <-------------------------------------------------
           反向查詢表名小寫ad.author:ad.author
'''

基於雙下劃線的跨表查詢(基於join實現)

#1 查詢python 這本書出版社的名字和郵箱
ret = models.Book.objects.filter(title='python').values('publish__name')
ret = models.Publish.objects.filter(book__title="python").values('name','email')
#2 蘋果出版社出版的所有書籍的名稱
ret = models.Publish.objects.filter(name='蘋果出版社').values_list('book__title')
ret = models.Book.objects.filter(publish__name="
蘋果出版社").values('title')

#3 查詢python書籍作者的年齡
ret = models.Book.objects.filter(title='python').values('authors__age')

#4 查詢alex出版過的所有書籍名稱
models.Author.objects.filter(name='alex').values('book__title')
models.Book.objects.filter(authors__name
='Alex').values('title')

#5 查詢alex的手機號
models.Author.objects.filter(name='Alex').values('authordetail__tel')
models.AuthorDetail.objects.filter(author__name
='Alex').values('tel')

#6 查詢手機號為110的作者的名稱
models.Author.objects.filter(authordetail__tel=110).values('name')
models.AuthorDetail.objects.filter(tel
=110).values('author_name')

#########連續跨表########

# 查詢人民出版社出版過的所有書籍的名字以及作者的姓名
publish.objects.filter(name="蘋果出版社").values("book__title","book__authors__name")
#手機號以110開頭的作者出版過的所有書籍名稱以及出版社名稱
ret = models.AuthorDetail.objects.filter(tel=110).values('author__book__title','author__book__publish__name')

#########聚合分組查詢######

#查詢所有書籍的平均價格
  from django.db.models import Avg,Max,Sum,Min,Count
  models.Book.objects.all().aggregate(priceAvg=Avg("price"))
  print(ret) #{"price_avg":123}
  #查詢所有書籍的個數
  models.objects.all().aggregate(c=Count("nid"))
  #分組
  #單表分組查詢
  #查詢書籍表每一個出版社id以及對應的書籍數
  select publish_id,Count(1) from book group by publish_id;
  #key:annotate()前values哪一個字段就按哪一個字段group by
  models.Book.objects.values("publish_id").annotate(count=Count(1))

#跨表分組查詢

# 查詢每一個出版社的名稱以及對應的書籍平均價格
ret = models.Publish.objects.values("name","email").annotate(book_count=Avg('book__price'))
# 查詢每一個出版社的名稱以及對應的書籍數
ret = models.Publish.objects.values("name").annotate(book_count=Count('book'))
# 查詢每一個作者的名字以及出版的書籍的最高價格
ret = models.Author.objects.values('name').annotate(max_price=Max('book__price'))
# 统计不止一个作者的图书:
ret = models.Book.objects.annotate(c=Count('authors')).filter(c__gt=1)
   select `bookstore_book`.`title`,Count(`bookstore_book_authors`.`author_id`) as author_count from bookstore_book
              inner join bookstore_book_authors
              on `bookstore_book`.`nid` = `bookstore_book_authors`.`book_id`
              group by `bookstore_book`.`nid`
              having author_count >=1

猜你喜欢

转载自www.cnblogs.com/jbite9057/p/11841022.html