判負環
阿新 • • 發佈:2022-05-13
Django(七)
聚合查詢
'''沒有分組也可以使用聚合函式 預設整體就是一組''' MySQL聚合函式:max\min\sum\count\avg '''使用時要先匯入模組,查詢操作時通過.aggregate(聚合函式('欄位'))操作''' eg: # from django.db.models import Max,Min,Count,Avg,Sum # # 查詢價格最高的書的價格 # res = models.Book.objects.aggregate(Max('price')) # print(res) # {'price__max': Decimal('80.00')} # 多重操作(中間逗號隔開) # res = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Sum('price'),Avg('price'))
分組查詢
mysql分組操作:group by ORM執行分組操作:如果報錯 可能需要去修改sql_mode 移除 only_full_group_by from django.db.models import Count, Min, Sum # # 統計每本書的作者個數 # res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num') # print(res) # <QuerySet [{'title': 'aaa', 'author_num': 1}, {'title': 'petter100', 'author_num': 1}, {'title': '三國演義', 'author_num': 1}, {'title': '紅樓夢', 'author_num': 1}]> # # 統計每個出版社賣的最便宜的書的價格 # res = models.Publisher.objects.annotate(min_book = Min('book__price')).values('name','min_book') # print(res) # <QuerySet [{'name': '老男孩出版社', 'min_book': Decimal('50.00')}]> # # 統計不止一個作者的圖書 # res = models.Book.objects.annotate(author_num=Count('authors__id')).filter(author_num__gt=1).values('title','author_num') # print(res) # <QuerySet []> # # 統計每個作者出的書的總價格 # res = models.Author.objects.annotate(total = Sum('book__price')).values('name','total') # print(res) # <QuerySet [{'name': 'petter', 'total': Decimal('250.00')}]> '''上述查詢是以每個表為單位做分組,以欄位為單位分組只需在annotate前面加一個values指定欄位即可''' # # 統計每個出版社主鍵值對應的書籍個數 # res = models.Book.objects.values('publisher__id').annotate(book_num=Count('id')).values('publisher__name','book_num') # print(res) # <QuerySet [{'publisher__name': '老男孩出版社', 'book_num': 4}]>
F查詢
""" 當表中已經有資料的情況下 新增額外的欄位 需要指定預設值或者可以為null 方式1 IntegerField(verbose_name='銷量',default=1000) 方式2 IntegerField(verbose_name='銷量',null=True) 方式3 在遷移命令提示中直接給預設值 """ from app01 import models from django.db.models import F, Value from django.db.models.functions import Concat # # 查詢庫存大於銷量的書籍 # res = models.Book.objects.filter(stock__gt=F('sales')) # print(res) # <QuerySet [<Book: 書籍物件bbb>]> # # 將所有書的價格提升1000塊 # models.Book.objects.update(price=F('price')+1000) # res = models.Book.objects.all().values('price') # print(res) # <QuerySet [{'price': Decimal('2000.00')}, {'price': Decimal('2000.00')}, {'price': Decimal('2000.00')}]> # # 將所有書的名稱後面加上_爆款字尾 # models.Book.objects.update(title=Concat(F('title'),Value('_爆款'))) # res = models.Book.objects.all() # print(res) # <QuerySet [<Book: 書籍物件aaa_爆款>, <Book: 書籍物件bbb_爆款>, <Book: 書籍物件ccc_爆款>]> ''' F查詢主要用於查詢條件左右兩表都需要當前資料的情況 '''
Q查詢
from django.db.models import Q
# # 查詢價格大於20000或者賣出大於1000的書籍
# res = models.Book.objects.filter(Q(price__gt=20000)|Q(sales__gt=1000)).values('title','price','sales') # '|'代表or,','代表and
# print(res) # <QuerySet [{'title': 'aaa_爆款', 'price': Decimal('200000.00'), 'sales': 200}, {'title': 'bbb_爆款', 'price': Decimal('2000.00'), 'sales': 2000}]>
# # 查詢庫存不大於1000的書籍
# res = models.Book.objects.filter(~Q(stock__gt=1000)).values('title','stock') # ~就是非的意思
# print(res) # <QuerySet [{'title': 'aaa_爆款', 'stock': 1000}, {'title': 'ccc_爆款', 'stock': 800}]>
'''
Q物件進階用法
filter(price=100)
filter('price'=100)
當我們需要編寫一個搜尋功能 並且條件是由使用者指定 這個時候左邊的資料就是一個字串
'''
q_obj = Q()
q_obj.connector = 'or' # 預設是and 可以改為or
q_obj.children.append(('price__gt',20000))
q_obj.children.append(('maichu__gt',1000))
res = models.Book.objects.filter(q_obj)
print(res.query)
ORM查詢優化
"""
在IT行業 針對資料庫 需要儘量做 能不'麻煩'它就不'麻煩'它
"""
# 1.orm查詢預設都是惰性查詢(能不消耗資料庫資源就不消耗)
光編寫orm語句並不會直接指向SQL語句 只有後續的程式碼用到了才會執行
# 2.orm查詢預設自帶分頁功能(儘量減輕單次查詢資料的壓力)
"""前幾年django面試經常問"""
# only與defer
only:把查詢結果封裝成一個個的物件,後面可以通過點的方式取值,不會走資料庫查詢,如果點選了物件沒有的資料
defer:與only相反,物件點括號內出現的欄位會走資料庫查詢,如果點選了括號內沒有的欄位也可以獲取到資料 每次都不會走資料庫查詢
eg:
res = models.Book.objects.only('title', 'price').first()
print(res.price) # 200000.00
print(res.title) # aaa_爆款
print(res.sales) # 200
# select_related和prefetch_related
select_related:類似於inner join,連線表再查詢,所有的結果封裝到查詢的物件中,後續物件通過正反向查詢跨表,內部不會再走資料庫查詢
prefetch_related:將多次查詢之後的結果封裝到資料物件中 後續物件通過正反向查詢跨表 內部不會再走資料庫查詢
ORM常見欄位
欄位 | 功能 |
---|---|
AutoField() | 定義主鍵 |
CharField() | 定義字串 |
IntergerField() | 定義整型 |
DecimalField() | 定義decimal型別 |
DateField() | 定義date日期型別 |
DateTimeField() | 定義datetime日期型別 |
BigIntergerField() | 長整型 |
BooleanField() | 布林值 |
TextField() | 儲存大段文字 |
FileField() | 傳檔案自動儲存到指定位置並存檔案路徑 |
EmailField() | 儲存email |
# 自定義欄位型別
class MyCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super().__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
ORM欄位常用引數
引數 | 功能 |
---|---|
primary_key | 主鍵 |
max_length | 最大字元長度 |
verbose_name | 欄位簡介 |
null | 空 |
default | 預設值 |
max_digits | decimal最大長度 |
decimal_places | decimal小數點後位數 |
unique | 唯一 |
db_index | 索引 |
auto_now | 表改變自動更新日期 |
auto_now_add | 建立記錄新增日期 |
choices | 類似於列舉 |
to | 建立外來鍵指定被關聯內容 |
to_field | 建立外來鍵指定被關聯內容 |
db_constraint | 是否在資料庫中建立外來鍵約束 |
related_name | 修改正向查詢的欄位名 |
# choices的使用
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
gender_chioce = (
(1,'male'),
(2,'female')
)
gender = models.IntegerField(chioces=gender_chioce)
res = models.User.objects.get('pk=1')
res.get_gender_display() # 'male'
# 如果gender=1,display獲取到的就是male
# 如果gender=2,display獲取到的就是female
# 如果gender的值不存在,直接返回數值
事務操作
MySQL事務:四大特性(ACID)
原子性
一致性
獨立性
永續性
mysql操作:
start transcation; # 開啟事務
rollback; # 回滾
commit; # 提交事務
from django.db import transaction
try:
with transaction.atomic():
pass
except Exception:
pass
'''執行完成自動提交,異常後自動回滾'''
ORM執行原生SQL
# 方式一
from django.db import connection, connections
cursor = connection.cursor()
# cursor = connections['default'].cursor()
cursor.execute("""SELECT * from app01_book where id = %s""", [1]) # 條件引數必出放到SQL語句外面,否則報錯
res = cursor.fetchone()
print(res) # (1, 'aaa_爆款', 1000, 200, Decimal('200000.00'))
# 方式二
res = models.Book.objects.extra(
select={'newid': 'select count(1) from app01_book where id=%s'},
select_params=[1, ],
)
print(res) # <QuerySet [<Book: 書籍物件aaa_爆款>, <Book: 書籍物件bbb_爆款>, <Book: 書籍物件ccc_爆款>]>
多對多三種建立方式
# 全自動(常見)
orm自動建立第三張表 但是無法擴充套件第三張表的欄位
authors = models.ManyToManyField(to='Author')
# 全手動(使用頻率最低)
優勢在於第三張表完全自定義擴充套件性高 劣勢在於無法使用外來鍵方法和正反向
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')
# 半自動(常見)
正反向還可以使用 並且第三張表可以擴充套件 唯一的缺陷是不能用
add\set\remove\clear四個方法
class Book(models.Model):
title = models.CharField(max_length=32)
authors = models.ManyToManyField(
to='Author',
through='Book2Author', # 指定表
through_fields=('book','author') # 指定欄位
)
class Author(models.Model):
name = models.CharField(max_length=32)
'''多對多建在任意一方都可以 如果建在作者表 欄位順序互換即可'''
books = models.ManyToManyField(
to='Author',
through='Book2Author', # 指定表
through_fields=('author','book') # 指定欄位
)
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')