1. 程式人生 > 遊戲 >《怪物獵人崛起:曙光》新映像見聞錄 阿爾洛教官

《怪物獵人崛起:曙光》新映像見聞錄 阿爾洛教官

目錄

聚合查詢

在ORM中也有相應的方法與MySQL中的聚合函式作用一致。

一共有五個聚合函式:

方法 作用
Max(欄位) 返回欄位中資料最大值
Min(欄位) 返回欄位中資料最小值
Sum(欄位) 返回欄位中資料總和
Count(欄位) 返回欄位中資料個數
Avg(欄位) 返回欄位中資料平均值

在使用以上五個聚合函式是需要先匯入才能使用:

from django.db.models import Max,Min,Sum,Count,Avg

使用:統計Student表中score欄位各項資料

res = models.Student.objects.aggregate(
    Max('score'),
    Min('score'),
    Sum('score'),
    Avg('score'),
    Count('score')
)

分組查詢

ORM分組查詢使用方法annotate()。

現有如下表:

  • 作者(編號,姓名,性別)
  • 書本(編號,書名,價格,作者編號)

以欄位為單位分組

要求:統計作者中各個性別的人數。

res = models.Author.objects.values('sex').annotate(sex_count=Count('pk')).values('sex','sex_count')
print(res)

以表為單位做分組

要求:統計每個作者出的書本數量。

res = models.Author.objects.annotate(book_count=Count('book__pk')).values('name','book_count')
print(res)

上述程式碼表示對作者表進行分組,並對書本編號進行統計,annotate()中的book_count是自己起的別名。

要求:統計每個作者出的最便宜的價格。

res = models.Author.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res)

F與Q查詢

F方法

如果我們想要讓兩個欄位進行比較篩選,或者是讓欄位資料在原來的基礎上繼續修改,這時就需要用到F()方法了。

匯入:

from django.db.models import F

查詢學生中數學成績(math)高於英語(english)的學生:

res = models.Student.objects.filter(math__gt=F('english'))

把所有書本的價格提升10元:

models.Book.objects.update(price=F('price')+10)

把所有書本的後面加上"(爆款)"(字串拼接需要額外兩個方法):

from django.db.models import Value
from django.db.models.functions import Concat
models.Book.objects.update(name=Concat(F('name'), Value('(爆款)')))

Q方法

filter()方法可以填寫多個條件,每個條件逗號隔開,條件之間預設是and關係,無法直接修改。

如果想要讓多個條件之間有更多的關係(比如or、not),需要用到Q方法。

使用Q方法後,,(逗號)隔開代表and,|(管道符)隔開代表or,~(波浪號)隔開代表not。

匯入:

from django.db.models import Q

查詢書本價格(price)大於50或者數量(quantity)大於50的書本

res = models.Book.objects.filter(
    Q(price__gt=50) | Q(quantity__gt=50)
)

查詢書本名稱(name)不包含'J'的書本:

res = models.Book.objects.filter(
    ~Q(name__contains='J')
)

進階

我們都知道,filter()內部不能使用字串傳參,比如filter('price'=50)這種,也就是說我們無法讓使用者自己輸入欄位名和欄位值篩選資料,但是使用Q方法就可以做到。

q_obj = Q()  # 獲取Q物件
field = input('請輸入欄位名:')
value = input('請輸入欄位值:')
q_obj.children.append((field,value))  # 新增條件
res = models.Book.objects.filter(q_obj)  # 篩選
print(res)

還可以設定條件之間的關係:

q_obj = Q()
q_obj.connector = 'or'  # 用於表示條件之間的關係,預設為and
q_obj.children.append(('price__gt',50))
q_obj.children.append(('quantity__gt',50))
res = models.Book.objects.filter(q_obj)
print(res.query)

ORM查詢優化

1.ORM查詢預設都是惰性查詢(能不消耗資料庫資源就不消耗)

編寫ORM語句並不會直接使用SQL語句,只有後續的程式碼用到了才會執行。

2.ORM查詢預設自帶分頁功能(儘量減輕單次查詢資料的壓力)

每次執行SQL都會限制查詢資料數量。

除了values()可以查詢指定欄位外,還有only()、defer()、select_related()、prefetch_related()。

only()與defer()

only()

only()返回物件結果集,獲取only()中指定的欄位不會再次執行SQL語句,但是如果獲取沒有指定的欄位,會去執行SQL語句獲取結果。

res = models.Book.objects.only('name','price')
for i in res:
    print(i.quantity)  # 獲取沒有指定的欄位

defer()

defer()與only()剛好相反,獲取defer()中指定的欄位會再次執行SQL語句獲取結果,但是如果獲取沒有指定的欄位,不會去執行SQL語句。

res = models.Book.objects.defer('name','price')
for i in res:
    print(i.name)  # 獲取指定的欄位

select_related()

select_related()括號內只能傳一對一和一對多欄位,不能傳多對多欄位或者其他欄位。

相當於連表操作,使用join一次性連線之後的大表中所有的資料全部封裝到資料物件中,後續使用物件跨表查詢都不會執行SQL語句。

res = models.Book.objects.select_related('author')
for i in res:
    print(i.name)
    print(i.author.name)

prefetch_related()

prefetch_related()括號內只能傳一對一、一對多、多對多欄位,不能傳其他欄位。

相當於子查詢,會分開操作查詢語句,將多次查詢之後的結果封裝到資料物件中,後續使用物件跨表查詢都不會執行SQL語句。

res = models.Book.objects.prefetch_related('author')
for i in res:
    print(i.name)
    print(i.author.name)

ORM常見欄位

常見欄位 描述
AutoField() 自動增長int型別
CharField(max_length=) varchar型別,必須提供max_length引數指定長度
IntergerField() int型別
DecimalField(max_digits=, decimal_places=) decimal型別,總位數max_digits,小數位數decimal_places
DateField() date型別,提供auto_now和auto_now_add引數
DateTimeField() datetime型別,提供auto_now和auto_now_add引數
BigIntergerField() bigint型別
BooleanField() 布林值,存0和1
TextField() 儲存大段文字
FileField() 傳檔案時會自動儲存到指定位置並只存檔案路徑
EmailField() varchar(254)
ForeignKey(to=) 一對多外來鍵關係,to指定有關係的表
OneToOneField(to=) 一對一外來鍵關係,to指定有關係的表
ManyToManyField(to=) 多對多外來鍵關係,to指定有關係的表

自定義欄位型別

自定義一個char型別的方法:

# 自定義欄位型別
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

欄位重要引數

重要引數 描述
primary_key 是否為主鍵
null 是否可以為空
unique 是否唯一
db_index 是否設定索引
default 設定預設值
max_length 設定長度
verbose_name 給欄位起別名
choices 給定一些選擇,有對應關係就拿,沒有還是本身
日期欄位引數
auto_now 是否每次更新資料時都要更新該欄位
auto_now_add 是否新增資料時將當前時間新增到該欄位
Decimal欄位引數
max_digits 設定Decimal欄位總位數
decimal_places 設定Decimal欄位小數位數
外來鍵欄位
to 設定要關聯的表
to_fileld 設定要關聯的表的欄位
on_delete 設定當刪除關聯表中的資料時,當前表與其關聯的行的行為
db_constraint 是否在資料庫中建立外來鍵約束,預設為True

choices引數

設定

class User(models.Model):
    gender_choice = (
        (1, '男性'),
        (2, '女性')
    )
    gender = models.IntegerField(choices=gender_choice)

取值的時候使用物件.get_xxx_display()來獲取choices後面具體的值,當choices中沒有該資料對應的時候獲取的仍是數字自己

User表

id gender
1 1
2 4
user_obj = models.Userinfo.objects.get(pk=1)
print(user_obj.get_gender_display())  # 男

user_obj = models.Userinfo.objects.get(pk=2)
print(user_obj.get_gender_display())   # 4

on_delete引數

on_delete有如下選擇:

on_delete值 描述
models.CASCADE 刪除關聯資料,與之關聯也刪除
models.DO_NOTHING 刪除關聯資料,引發錯誤IntegrityError
models.PROTECT 刪除關聯資料,引發錯誤ProtectedError
models.SET_NULL 刪除關聯資料,與之關聯的值設定為null(前提FK欄位需要設定為可空)
models.SET_DEFAULT 刪除關聯資料,與之關聯的值設定為預設值(前提FK欄位需要設定預設值)
models.SET 刪除關聯資料,與之關聯的值設定為指定值或是可執行物件的返回值

事務操作

使用:

from django.db import transaction
with transaction.atomic():
    pass

with上下文管理開始執行代表事務開始,中間報錯自動回滾,結束with語句自動提交事務。

ORM執行原生SQL

方式一:

from django.db import connection, connections
cursor = connection.cursor()  
cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
cursor.fetchone()

方式二:

models.UserInfo.objects.extra(
                    select={'newid':'select count(1) from app01_usertype where id>%s'},
                    select_params=[1,],
                    where = ['age>%s'],
                    params=[18,],
                    order_by=['-age'],
                    tables=['app01_usertype']
                )

多對多三種建立方式

全自動

orm自動建立第三張表,但是無法擴充套件第三張表的欄位。

class Student(models.Model):
	courses = models.ManyToManyField(to='Course')

全手動

優勢在於第三張表完全自定義擴充套件性高,劣勢在於無法使用外來鍵方法和正反向查詢。

class Student(models.Model):
    title = models.CharField(max_length=32)
class Course(models.Model):
    name = models.CharField(max_length=32)
class Student2Course(models.Model):
    student = models.ForeignKey(to='Student')
    course = models.ForeignKey(to='Course')

半自動

正反向查詢還可以使用,並且第三張表可以擴充套件,唯一的缺陷是不能用add\set\remove\clear四個方法。

class Student(models.Model):
    name = models.CharField(max_length=32)
    courses = models.ManyToManyField(
        to='Course',
        through='Student2Course',  # 指定表
        through_fields=('student', 'course')  # 指定欄位,注意順序
    )
class Course(models.Model):
    name = models.CharField(max_length=32)
class Student2Course(models.Model):
    student = models.ForeignKey(to='Student')
    course = models.ForeignKey(to='Course')

多對多建在任意一方都可以,如果建在Course表,欄位順序互換即可。