1. 程式人生 > 其它 >雙下查詢,ORM建立外來鍵,多表查詢

雙下查詢,ORM建立外來鍵,多表查詢

雙下劃線查詢方法

比較運算

# 關鍵字:
    大於:		__gt
    小於:		__lt
    大於等於:		__gte
    小於等於:		__lte
# 舉例:
    res = models.User.objects.filter(age__gt=18)
    print(res)   # 年齡大於18
    res1 = models.User.objects.filter(age__lt=18)
    print(res)   # 年齡小於18
    res2 = models.User.objects.filter(age__gte=18)
    print(res2)  # 年齡大於等於18
    res3 = models.User.objects.filter(age__lte=18)
    print(res3)   # 年齡小於等於18

在某一資料集內:

# 關鍵字:__in=['資料集']

# 舉例:
    res = models.User.objects.filter(age__in=[10,20,30,40])
    print(res)

在某一範圍內:

# 關鍵字:__range=[]
# 舉例:
    res = models.User.objects.filter(age__range=[19,40]) # 包含19和40
    print(res)

模糊查詢:

# 關鍵字:__contain=''  區分大小寫
	 __icontain=''  不區分大小寫
# 舉例:
查詢姓名中包含字母k的使用者
    res = models.User.objects.filter(name__contains='k')
    print(res)
    res1 = models.User.objects.filter(name__icontains='k')
    print(res1)

以什麼開頭/結尾:

# 關鍵字:__startwith=''  以什麼開頭
	 __endswith=''	 以什麼結尾
    	 __istartwith=''  不區分大小寫
         __iendswith=''   不區分大小寫
# 舉例:
models.User.objects.filter(name_ _startswith="n" )

models.User.objects.filter(name_ _endswith="n" )

按照日期查詢:

# 關鍵字:
    __month='1'   # 按照月份取
    __year='2020'  # 按照年份
    __day='29'    # 按照天篩選

# 舉例:
    res = models.User.objects.filter(register_time__month='01')
    print(res)
    res1= models.User.objects.filter(register_time__day='02')
    print(res1)
    res3 = models.User.objects.filter(register_time__year='2022')
    print(res3)
    res4 = models.User.objects.filter(register_time__year='2022',register_time__month='02')
    print(res4)

ORM建立外來鍵

以書籍,出版社,作者,作者資訊這4張表為例

書籍和出版社的關係:
  一本書籍只能由一個出版社出版,一個出版社可以出版多本書。
  關係為:一對多(ForeignKey),書籍是多所以外來鍵建立在書籍表中。

書籍和作者的關係:
  一本書可以由多個作者創作,一個作者同樣也可以創作多本書。
  關係為:多對多(ManyToManyField),需要建立第三張表來表示關係

作者和作者資訊的關係:
  一條資訊對應一個作者,一個作者對應一條資訊。
  關係為:一對一(OneToOneField),外來鍵應建立在查詢頻率較高的表中。
  
一對多外來鍵關係  
    """在orm中 外來鍵欄位建在多的一方"""
多對多外來鍵關係
    """在orm中 可以直接寫在查詢頻率較高的表中(自動建立第三張表)"""
一對一外來鍵關係
    """在orm中 直接寫在查詢頻率較高的表中"""


"""
ManyToManyField不會在表中建立實際的欄位 而是告訴django orm自動建立第三張關係表
ForeignKey、OneToOneField會在欄位的後面自動新增_id字尾 如果你在定義模型類的時候自己新增
了該字尾那麼遷移的時候還會再次新增_id_id 所以不要自己加_id字尾

ps:三個關鍵字裡面的引數
    to用於指定跟哪張表有關係 自動關聯主鍵
    to_field\to_fields  也可以自己指定關聯欄位
"""
#書籍
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    # 一對多
    publish = models.ForeignKey(to='Publish')
    # 多對多
    authors = models.ManyToManyField(to='Author')  # 自動建立書籍和作者的第三張關係表

#出版
class Publish(models.Model):
    title = models.CharField(max_length=32)

#作者
class Author(models.Model):
    name = models.CharField(max_length=32)
    # 一對一
    author_detail = models.OneToOneField(to='AuthorDetail')

#作者資訊
class AuthorDetail(models.Model):
    addr = models.CharField(max_length=32)
    phone = models.BigIntegerField()

ORM外來鍵欄位操作

一對一,一對多(OneToOneField,ForeignKey)

新增外來鍵欄位值:
    #第一種方法
    models.Book.objects.create(title='JAVA',price=123456,publish_id=1) # 直接填寫關聯資料的主鍵值
    #第二種方法
    publish_obj = models.Publish.objects.filter(pk=2).first() # 獲取外來鍵物件
    models.Book.objects.create(title='JS',price=11111,publish=publish_obj)

修改外來鍵欄位值:
    #第一種方法
    models.Book.objects.filter(pk=1).update(publish_id=2) # 直接修改publish_id的值
    #第二種方法
    publish_obj = models.Publish.objects.filter(pk=2).first() # 先獲取物件,這裡是修改出版社那麼要先獲取對應出版社物件
    models.Book.objects.filter(pk=1).update(publish=publish_obj) # 修改publish

多對多(ManyToManyField)

 # 新增關係
    #第一種方法
    book_obj = models.Book.objects.filter(pk=2).first() # 先獲取對應書籍物件
    book_obj.authors.add(1)  # 然後給書籍物件的authors欄位傳入作者的id # 在第三張關係表中新增資料
    book_obj.authors.add(1, 3)  #可以直接填寫資料主鍵值
    #第二種方法
    author_obj1 = models.Author.objects.filter(pk=3).first() # 先獲取作者物件
    author_obj2 = models.Author.objects.filter(pk=4).first()
    book_obj.authors.add(author_obj1)
    book_obj.authors.add(author_obj1,author_obj2) # 會在第三張表中新增2條資料(2,3)(2,4)
    #修改關係
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.set([3, ])
    book_obj.authors.set([1, 2])
    author_obj1 = models.Author.objects.filter(pk=3).first()
    author_obj2 = models.Author.objects.filter(pk=4).first()
    book_obj.authors.set([author_obj1, ])
    book_obj.authors.set([author_obj1, author_obj2])
    #移除關係
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.remove(3)
    book_obj.authors.remove(3,4)
    author_obj1 = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    book_obj.authors.remove(author_obj1)
    book_obj.authors.remove(author_obj1,author_obj2)
    #清空關係
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.clear()
  1.第三張關係表建立資料
	book_obj = models.Book.objects.filter(pk=1).first()
  	book_obj.authors.add()
  	括號內可以放主鍵值也可以放資料物件 並且都支援多個
  2.第三張關係表修改資料
  	book_obj.authors.set()
    	括號內必須是一個可迭代物件 元素同樣支援主鍵值或者資料物件
  3.第三張關係表刪除資料
  	book_obj.authors.remove()
    	括號內可以放主鍵值也可以放資料物件 並且都支援多個
  4.第三張關係表清空指定資料
  	book_obj.authors.clear()
    	括號內無需傳值 直接清空當前表在第三張關係表中的繫結記錄

正向查詢和反向查詢

  如果一張表有外來鍵欄位,並且是從這張表開始查詢的,那麼就叫作正向查詢。
  相反的,如果從關聯表開始查詢的,就叫反向查詢。

  由書籍查詢出版社 外來鍵欄位在書籍表中 那麼書查出版社就是'正向'
  由出版社查詢書籍 外來鍵欄位不在出版社表 那麼出版社查書就是'反向'

	"""
 	查詢口訣
 		正向查詢按外來鍵欄位名
 		反向查詢按表名小寫
 	"""

多表查詢

表資訊

#書籍
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    # 一對多
    publish = models.ForeignKey(to='Publish')
    # 多對多
    authors = models.ManyToManyField(to='Author')  # 自動建立書籍和作者的第三張關係表

#出版
class Publish(models.Model):
    title = models.CharField(max_length=32)

#作者
class Author(models.Model):
    name = models.CharField(max_length=32)
    # 一對一
    author_detail = models.OneToOneField(to='AuthorDetail')

#作者資訊
class AuthorDetail(models.Model):
    addr = models.CharField(max_length=32)
    phone = models.BigIntegerField()

基於物件的跨表查詢(子查詢)

正向查詢
1.查詢Python程式設計書籍對應的出版社
  (1)先獲取書籍物件
        book_obj = models.Book.objects.filter(title='Python程式設計').first()
  (2)進行跨表查詢,從書籍找到出版社是正向查詢,使用外來鍵欄位名
        res = book_obj.publish # 返回的是對應的出版社物件
        print(res.title) # 上海出版社
    
2.查詢python程式設計書籍創作的作者
    # 首先先獲取書籍物件
    book_obj = models.Book.objects.filter(title='Python程式設計').first()
    # 進行跨表查詢,從書籍找到出版社是正向查詢,使用外來鍵欄位名
    # res = book_obj.authors
    # print(res) # app01.Author.None # 此時返回none,如果返回有多個還需要加all()
    res = book_obj.authors.all() # 返回多個物件
    print(res) # <QuerySet [<Author: Author object>, <Author: Author object>]>

反向查詢
3.查詢上海出版社出版的書籍
#首先獲取出版社物件
    publish_obj = models.Publish.objects.filter(title='上海出版社').first()
    #進行跨表查詢,從出版社找到書籍是反向查詢(外來鍵不在出版社表中),使用表名小寫
    # res = publish_obj.book_set # 反向查詢時表名小寫還需要加上 _set
    # print(res) # app01.Book.None
    #由於一個出版社可以出版多本書籍,返回結果可能是多個,還需要加上 all()
    res = publish_obj.book_set.all() #返回多個書籍物件
    print(res) # <QuerySet [<Book: Book object>, <Book: Book object>]>

4.查詢電話為1的作者(在一對一關係中的反向查詢表名小寫後不要跟 _set)
    author_detail_obj = models.AuthorDetail.objects.filter(phone=1).first()
    res = author_detail_obj.author # 返回作者物件
    print(res.name)  # 張三

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

1.查詢Python程式設計書籍對應的出版社名稱
      res = models.Book.objects.filter(title='Python程式設計').values('publish__title')
      print(res) # <QuerySet [{'publish__title': '上海出版社'}]>

2.查詢作者張三的手機號和地址
      res = models.Author.objects.filter(name='張三').values('author_detail__phone','author_detail__addr')
      print(res) # <QuerySet [{'author_detail__phone': 1, 'author_detail__addr': '上海'}]>

雙下劃線查詢擴充套件

1.查詢Python程式設計書籍對應的出版社名稱
    方法一:
    res = models.Publish.objects.filter(book__title='Python程式設計') # 返回出版社物件<QuerySet [<Publish: Publish object>]>
    print(res[0].title) # 上海出版社
    方法二:
    res = models.Publish.objects.filter(book__title='Python程式設計').values('title')
    print(res) # <QuerySet [{'title': '上海出版社'}]>
    print(res[0].get('title')) # 上海出版社
    方法三:
    res = models.Publish.objects.filter(book__title='Python程式設計').first()
    print(res.title) # 上海出版社

2.查詢作者王五的手機號和地址
    res = models.AuthorDetail.objects.filter(author__name='王五').values('phone','addr')
    print(res) # <QuerySet [{'phone': 3, 'addr': '北京'}]>
    print(res[0].get('phone')) # 3
    print(res[0].get('addr')) # 北京

'''連續跨表操作'''
1.查詢python程式設計書籍對應的作者的手機號
    res = models.Book.objects.filter(title='PYthon程式設計').values('authors__author_detail__phone')
    print(res) # <QuerySet [{'authors__author_detail__phone': 1}, {'authors__author_detail__phone': 2}]>

如何檢視SQL語句

方式1:如果結果集物件是queryset 那麼可以直接點query檢視
方式2:配置檔案固定配置
  	適用面更廣 只要執行了orm操作 都會列印內部SQL語句
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}