1. 程式人生 > >Django之模型層-多表操作

Django之模型層-多表操作

自動 int its 數量 val foreign 編寫 ces first

多表操作

數據庫表關系

  1. 一對多:兩個表之間的關系一旦確定為一對多,必須在數據多的表中創建關聯字段
  2. 多對多:兩個表之間的關系一定確定為多對多,必須創建第三張表(關聯表)
  3. 一對一:一旦兩個表之間的關系確定為一對一,在兩種表中任意一張表中建立關聯字段unique

ORM生成關聯表模型

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    # 出版社信息
    # 一對多
    publish = models.ForeignKey(to=‘Publish‘,to_field=‘id‘,on_delete=models.CASCADE)

    # 多對多
    author = models.ManyToManyField(to=‘Author‘)
    def __str__(self):
        return self.title

class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    email = models.EmailField()

class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 一對一
    authorDetails = models.OneToOneField(to=‘AuthorDetails‘,to_field=‘id‘,on_delete=models.CASCADE)
    def __str__(self):
        return self.name

class AuthorDetails(models.Model):
    id = models.AutoField(primary_key=True)
    city = models.CharField(max_length=32)
    phone = models.IntegerField()

  • 創建表關系方法:
    • 一對一:OneToOneField()
    • 一對多:ForeignKey()
    • 多對多:ManyToManyField()
  • 表關系模型創建註意事項
    • 創建關聯表時不需要在關聯字段後面加_id,ORM會自動加

    • 關聯表關系:一對多關系
      to=表的時候可以加引號也可以不加,不加引號的話必須被關聯的表在關聯表上面,to_field也可以不寫主鍵,不寫的話默認是關聯表的主鍵
    • on_delete=models.CASCADE在一對多的時候必須要加,一對多的時候也必須要加,如果不加會報on_delete錯誤
    • null = True 允許關聯字段為空
    • 在生成表關系多對多的時候,會另外生成第三張表,不會在該表內生成

多表操作之添加記錄

添加記錄時先添加單表的記錄(不關聯其他表的表),插入時與單表插入一樣。然後插入與其他表關聯了的表的記錄,有兩種插入方式:

方式1:直接傳入一個關聯的鍵

Books.objects.create(b_name=‘紅樓夢‘,price=100,author_id=1,publish_id=2)

方式2:傳入一個模型對象

publish_obj = Publish.objects.filter(id=‘1‘)[0]
Books.objects.create(b_name=‘紅樓夢‘,price=100,author_id=1,publish=publish_obj)

在使用關聯字段的時候,可以使用字段名_id,也可以直接使用字段名,使用字段名是打印的一個模型對象,使用字段名_id的話打印的是一個關聯的鍵

book_obj = Books.objects.filter(bid=1)[0]
print(book_obj.b_name)
print(book_obj.publish) #Publish object (2)
print(book_obj.publish.p_name) #南京出版社
print(book_obj.publish_id) # 2

綁定多對多關系

book = Publish.objects.filter(id__gt=2).delete()
cao = Author.objects.get(name=‘曹雪芹‘)
luo = Author.objects.get(name=‘羅貫中‘)
book.author.add(cao,luo)

解除多對多的關系,先找到需要解除的對象

# 參數可以是一個主鍵也可以是模型對象
book.author.remove(1)

清空多對多關系

book.author.clear()

獲取一個模型所有的關聯對象

print(book.author.all())

設置多對多關系

# set函數相當於是先清空了(clear)數據,然後再重新賦值,賦值參數是一個可叠代對象
book.author.set(列表)

跨表查詢

正向查詢:假設關聯屬性在A表中,通過A查詢B對象就是屬於正向查詢,正向查詢按字段

反向查詢:假設關聯屬性在A表中,通過B查詢A對象就是屬於正向查詢,反向查詢按表名小寫_set

基於對象查詢(子查詢)

  • 一對多的查詢
# 一對多的正向查詢:查詢紅樓夢這本書的出版社名字
book = Book.objects.filter(title=‘紅樓夢‘)[0]
print(book.publish.name)

# 一對多的反向查詢:查某個出版社出版過的書籍
publish_obj = Publish.objects.get(name=‘南京出版社‘)
ret = publish_obj.book_set.all()
print(ret)
  • 多對多的查詢
# 多對多的正向查詢:查詢紅樓夢這本書所有作者的名字
book = Book.objects.filter(title=‘紅樓夢‘)[0]
ret = book.author.all()
print(ret)
# 多對多的反向查詢:查詢曹雪芹寫過的書
author = Author.objects.filter(name=‘曹雪芹‘)[0]
ret = author.book_set.all()
print(ret)
  • 一對一的查詢
    # 一對一的正向查詢:查詢名字為曹雪芹的所在城市
    auth = Author.objects.filter(name=‘曹雪芹‘).first()
    print(auth.authorDetails.city)

    # 一對一的反向查詢:查詢在江蘇的作者的名字
    ad = AuthorDetails.objects.filter(city=‘江蘇‘).first()
    print(ad.author.name)

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

正向查詢按字段,反向查詢按表名小寫

雙下劃線就相當於需要關聯哪一張表,相當於sql語句中的join

一對多

# 一對多的正向查詢查詢紅樓夢的出版社名字
# 方式1
ret = Book.objects.filter(title=‘紅樓夢‘).values(‘publish__name‘)
print(ret)
# 方式2
ret = Publish.objects.filter(book__title=‘紅樓夢‘).values(‘name‘)

多對多

 # 查詢紅樓夢的作者的名字
 # 方式1
ret = Book.objects.filter(title=‘紅樓夢‘).values(‘author__name‘)
print(ret)
 # 方式2
 ret = Author.objects.filter(book__title=‘紅樓夢‘).values(‘name‘)

一對一查詢

# 查詢曹雪芹所在的城市
# 正向查詢
ret = Author.objects.filter(name=‘曹雪芹‘).values(‘authorDetails__city‘)
# 反向查詢
ret = AuthorDetails.objects.filter(author__name=‘曹雪芹‘).values(‘city‘)
# print(ret)

連續跨表查詢

# 手機號以15開頭的作者出版過的書籍以及出版社的名稱
# 正向查詢
ret = Book.objects.filter(author__authorDetails__phone__startswith=151).values(‘title‘,‘publish__name‘)
# 反向查詢
ret = Author.objects.filter(authorDetails__phone__startswith=‘151‘).values(‘book__title‘,‘book__publish__name‘)
print(ret)

聚合查詢

aggregate()函數

# 查詢所有書籍的平均價格
# 聚合查詢:聚合函數aggregate
from django.db.models import Avg,Max,Min,Count,Sum
ret = Book.objects.all().aggregate(Avg(‘price‘)) #返回值是一個字典
print(ret)

分組查詢

annotate()

單表分組

單表分組查詢的ORM語法:單表模型.objects.values(‘group by字段‘).annotate(聚合函數("統計字段")

from django.db.models import Avg,Max,Min,Count,Sum
ret = Emp.objects.values(‘dep‘).annotate(avg_salary=Avg(‘salary‘))
print(ret)

多表分組查詢

多表查詢分組語句模型:

每一個後表模型.objects.value(‘主鍵‘).anntota(聚合函數(關聯表__ 字段)).values(‘表模型字段以及所有統計字段‘)

 # 查詢出版社名稱以及出版社出版的書籍數量
# 方式1
ret = Publish.objects.values(‘name‘).annotate(count=Count(‘book__title‘))
print(ret)
# 方式2
ret = Publish.objects.values(‘id‘).annotate(count=Count(‘book__title‘)).values(‘name‘,‘count‘)
print(ret)

# 查詢每一個作者出版過的書籍的最高價格
ret = Author.objects.values(‘id‘).annotate(max_price = Max(‘book__price‘)).values(‘name‘,‘max_price‘)
print(ret)

F 與 Q查詢

  • F查詢

用於在一張表內兩個字段進行比較查詢,F對象內放的是同一張表的字段,對表進行批量操作也可以使用該類

from django.db.models import F
# 查詢評論數大於閱讀數
ret = Book.objects.filter(comment_num__gt=F("reda_num"))

# 所有書籍的價格加10
Book.objects.all().update(price=F(‘price‘)+10)
  • Q查詢

filter()等方法中的關鍵字參數查詢都是一起進行‘AND‘的,如果需要執行更復雜的查詢,可以使用Q對象

Q對象可以使用&、|、~操作符組合起來使用並且可以使用括號進行分組編寫任意復雜的Q對象

查詢名字是紅樓夢的書籍或者價格大於20元的書籍
from django.db.models import F,Q
ret = Book.objects.filter(read_num__gt=F(‘comment_num‘))
print(ret)
ret = Book.objects.filter(Q(title=‘紅樓夢‘)|Q(price__gt=20))
print(ret)

Django之模型層-多表操作