django orm 多表查詢


Django多表ORM設計規則

1. 關聯表之間建議建立外鍵,但是可以取消關聯關系(db_constraint=False)
2. 關聯表之間的晚間字段建議采用對應類名的全小寫
3. 采用關聯表的主鍵或對象均能進行操作
'''
    書籍: Book: id name price publish_date publish author(多對多關聯字段)
    出版社: Publish:id name address
    作者: Author : id name author_detail
    作者詳情: AuthorDetail : id age telephone info
'''

創建數據表(Models)

# 一對多:出版社(一) 書籍(多,外鍵在多的一方,依賴於出版社)
# 一對一:作者詳情(一) 作者(一,外鍵在任意一方均可,一旦外鍵放在作者中,作者依賴於作者詳情)
# 多對多:作者(多)書籍(多)建立關系表(存放兩個表的外鍵信息 => 將建表轉化為關系對應字段)
# Book書籍:id  name  price  publish_date  publish(publish_id)
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    publish = models.ForeignKey(to='Publish', to_field='id')
    # 多對多關系字段,該字段不會再book表中形成字段,是用來創建關系表的
    author = models.ManyToManyField(to='Author')
​
# Author作者:id  name
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    # author_detail = models.ForeignKey(to='AuthorDetail', to_field='id', unique=True)
    author_detail = models.OneToOneField(to='AuthorDetail', to_field='id')
​
# AuthorDetail作者詳情: id  age  telephone  info
class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    age = models.IntegerField()
    telephone = models.IntegerField()
    # 存大文本
    info = models.TextField()
​
# Publish出版社:id  name  address
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    address = models.CharField(max_length=64)

一對多關系

# 規則
1. 關系中多的依賴於一的
2. Django 1.X版本中外鍵關聯默認由級聯刪除
   Django 2.X版本中外鍵需要手動設置級聯刪除(on_delete=models.CASCADE)

************************************************************
#
# 先有出版社,才有書籍
Publish.objects.create(name='xxx出版額社', address='SH')
# 外鍵為關聯對象
Book.objectes.create(name='python', price=88.88, publish_data='2018-08-08', publish=publish)
​
id = Publish.objects.create(name="小女孩出版社", address="宇宙中心").id
# 外鍵字段為關聯對象主鍵
Book.objects.create(name='滅霸Linux', price=120.00, publish_date='2015-8-8', publish_id=id)
​
# 刪除出版社,默認有級聯刪除,出版社出版的數據全會被刪除
Publish.objects.first().delete()
​
# 書籍的出版社修改必須為已存在的出版社
publish = Publish.objects.create(name="ssss出版社", address="御花園")
Book.objects.filter(pk=1).update(publish=publish)  # pk代表主鍵

一對一關系

規則


1. 通過外鍵所在表決定依賴關系
# 操作規則同一對多關系,有外鍵的表 依賴於 另一張表

# 增:遵循操作順序
author_detail = AuthorDetail.objects.create(age=8, telephone=13860357890, info="真的帥")
Author.objects.create(name='Alan', author_detail=author_detail)

# 刪:擁有級聯刪除
AuthorDetail.objects.first().delete()

# 改:一般不考慮該關聯字段

多對多關系

 

# 規則
1. 多對多關系存在表關系,關系表建議采用ManyToManyField字段處理
2. 需要手動創建關系表時, 字段中明確through與through_field值

**************************************************
通過關系表字段存在的類的對象獲取關系表 book.author
​
# 增:為書籍添加作者的主鍵或對象們
book.author.add(*args)
​
# 刪:刪除書籍已有作者的主鍵或對象們
book.author.remove(*args)
​
# 改:清空並添加作者的主鍵或對象 | 設置作者的主鍵或對象形式的列表
book.author.clear()
book.author.add(*args)
​
book.author.set([*args])

跨表查詢規則:

1. 正向逆向概念:從存放外鍵的表到關系表稱之為正向跨表查詢,反之稱之為逆向查詢
2. 正向查詢通過外鍵屬性名進行跨表查詢
3. 逆向查詢通過關聯表對應類名小寫進行跨表查詢

基於對象的跨表查詢

在跨表查詢的規則上,跨表查詢的結果為多條數據時需要在字段后添加_set
​
# 一對一
author = Author.objects.first()  # 查詢得到作者對象
author_detail = author.author_detail  # 基於對象跨表獲取作者詳情對象,正向通過字段名 author_detail
author = author_detail.author  # 基於對象跨表獲取作者對象,逆向通過表名小寫 author
# 一對多
book = Book.objects.first()  # 查詢得到書籍對象
publish = book.publish  # 獲取出版社對象,正向通過字段名 publish
book_list = publish.book_set.all()  # 獲取書籍對象們,逆向通過表名小寫 book,多條數據添加_set
# 多對多
book = Book.objects.first()  # 查詢得到書籍對象
author_list = book.author   # 獲取作者對象們,正向通過字段名 author
​
author = Author.objects.first()
book_list = author.book_set  # 獲取書籍對象們,逆向通過表名小寫 book,多條數據添加_set
'''
多級跨表
# 案例一:某作者出版的第一本書的出版社名字
# 作者 Author ->book表(逆向查詢, book_set)-> 第一本書first() ->出版社           publish-> name
author.book_set.first().publish.name
'''

基於下划線的跨表查詢

滿足跨表查詢規則
filter方法與values方法支持__查詢規則
​
# 案例
# 兩表關聯:查詢所有小於18歲作者的名字與實際年齡
author_dic = Author.objects.filter(author_detail_age_lt=18).values('name','author_detail_age')
​
# 多表關聯:查詢出版社在上海的出版過的所有書的 作者姓名、作者電話、具體出版社名 的相關信息
info_dic = Book.objects.filter(publish_address_contains='上海').values('author_name', 'author_author_detail_telephoone', 'publish_name')

 

# 直接導入django可以查看並用於django包相關模塊,但無法使用django創建的項目中的包

import django
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "duobiaochaxun.settings")
django.setup()

from app.models import Book, AuthorDetail, Author, Publish

# 一對多關系(publish和book book依賴於publish)

# 增加
publish = Publish.objects.create(name='老男孩出版社', address='上海浦東').id
publish1 = Publish.objects.create(name='小女孩出版社', address='上海虹橋').id
publish2 = Publish.objects.create(name='金沙江出版社', address='北京朝陽').id
Book.objects.create(name='西游記', price='33.33', publish_date='2018-01-01', publish_id=publish2)
Book.objects.create(name='東游記', price='44.44', publish_date='2018-02-02', publish_id=publish2)
Book.objects.create(name='愛麗莎', price='55.55', publish_date='2018-03-03', publish_id=publish1)
Book.objects.create(name='顧杜友', price='66.66', publish_date='2018-04-04', publish_id=publish1)
Book.objects.create(name='拍死你', price='77.77', publish_date='2018-05-05', publish_id=publish)
Book.objects.create(name='牛尼斯', price='88.88', publish_date='2018-06-06', publish_id=publish)


一對一關系 Author依賴於AuthorDetail
detail = AuthorDetail.objects.create(age=20, telephone=13333334444, info='Owen簡介')
detail1 = AuthorDetail.objects.create(age=19, telephone=14356789900, info='Zero簡介')
detail2 = AuthorDetail.objects.create(age=20, telephone=16678906677, info='Egon簡介')
detail3 = AuthorDetail.objects.create(age=21, telephone=18900123456, info='Lxx簡介')
detail4 = AuthorDetail.objects.create(age=17, telephone=16875435678, info='Yhh簡介')
Author.objects.create(name='Owen', author_detail=detail)
Author.objects.create(name='Zero', author_detail=detail1)
Author.objects.create(name='Egon', author_detail=detail2)
Author.objects.create(name='Lxx', author_detail=detail3)
Author.objects.create(name='Yhh', author_detail=detail4)

多對多關系
b1 = Book.objects.first()
b2 = Book.objects.all()[1]
b3 = Book.objects.all()[2]
b4 = Book.objects.all()[3]
b5 = Book.objects.all()[4]
b6 = Book.objects.last()
a1 = Author.objects.first()
a2 = Author.objects.all()[1]
a3 = Author.objects.all()[2]
a4 = Author.objects.all()[3]
a5 = Author.objects.last()

b1.author.add(a1, a2)
b2.author.add(a1, a2, a5)
b3.author.add(a4)
b4.author.add(a4)
b5.author.add(a1, a3, a4)
b6.author.add(a4, a5)


# 地址在北京的出版社出版的書名
# 價格超過50元的書籍的出版社名
books = Book.objects.filter(publish__address__contains='北京')
for book in books:
    print(book.name)
publish = Publish.objects.filter(book__price__gt=50).distinct()
for p in publish:
    print(p.name)


# 獲取所有名字里包含字母o(不區分大小寫)作者的電話號碼
# 年齡是20歲作者的作者名
authors = AuthorDetail.objects.filter(author__name__icontains='o')
for author in authors:
    print(author.telephone)
author = Author.objects.filter(author_detail__age=20)
for age in author:
    print(age.name)

# -- 獲取第三位作者出版過的書的書名
# -- 獲取最后一本書作者們的簡介
author = Author.objects.all()[2]
for book in author.book_set.all():
    print(book.name)
authors =  Book.objects.last().author.all()
for author in authors:
    print(author.author_detail.info)

# 獲取第一個出版社出版的最近一次出版的書的作者們的詳情
authors = Publish.objects.first().book_set.all().order_by('publish_date').last().author.all()
for author in authors:
    print(author.author_detail.info)
# 1. 找到第一個出版社 2.找到最后一本書 3.找到作者們
authors = Publish.objects.first().book_set.all().order_by('publish_date').last().author.all()
for author in authors:
    print(author.name)

# -- 獲取地址在上海的出版社名,與出版過的書名
# -- 獲取2018年出版的書名、書的價格與出版社名
publish = Publish.objects.filter(address__contains='上海').values('name','book__name')
print(publish)
books = Book.objects.filter(publish_date__year=2018).values('name', 'price', 'publish__name')
print(books)
# -- 獲取年齡小於20歲作者的名字、年齡、電話與簡介
print(Author.objects.filter(author_detail__age__lt=20).values('name', 'author_detail__age', 'author_detail__info'))

# -- 獲取名字中包含e(不區分大小寫)的作者出版過的書的書名與價格(需要去重)
# -- 獲取書籍價格不超過50元的作者名與作者電話(需要去重)
n_pr = Author.objects.filter(name__icontains='e').values('name','book__name', 'book__price').distinct()
print(n_pr)
#
name_tep = Book.objects.filter(price__lte=50).values('author__name', 'author__author_detail__telephone').distinct()
print(name_tep)
# -- 獲取在老男孩出版過書的年齡最大的作者的作者名、年齡、電話與簡介

info = Author.objects.filter(book__publish__name__contains='老男孩')\
    .values('name', 'author_detail__age', 'author_detail__telephone', 'author_detail__info', 'book__publish__name')\
    .order_by('author_detail__age').last()
print(info)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM