Django ORM之F與Q查詢


1、F查詢

我們構造的過濾器都只是將字段值與某個我們自己設定的常量做比較。如果我們要對兩個字段的值做比較,那該怎么做呢❓

Django 提供 F() 來做這樣的比較。F() 的實例可以在查詢中引用字段,來比較同一個 model 實例中兩個不同字段的值。

 

models.py

from django.db import models

# Create your models here.
class Product(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    maichu = models.IntegerField()
    kucun = models.IntegerField()

    def __str__(self):
        return '商品對象的名字:%s' %self.name

 

用的sqlite數據庫

image

F可以依次取出表中某個字段對應的值,當作篩選條件,實現動態比較的效果;

 

from django.test import TestCase

# Create your tests here.
import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day59.settings")
    import django
    django.setup()
    from app01 import models
    from django.db.models import F, Q

# F查詢
# 查詢賣出數大於庫存數的商品
res = models.Product.objects.filter(maichu__gt=F('kucun'))
print(res)

# 將所有的商品的價格提高100塊
models.Product.objects.update(price=F('price')+100)

# 將所有商品的名字后面都加一個爆款,Concat表示進行字符串的拼接操作,Value里是要新增的拼接值
from django.db.models.functions import Concat
from django.db.models import Value
models.Product.objects.update(name=Concat(('name'), Value('爆款')))

 

#Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操作。基於此可以對表中的數值類型進行數學運算➕➖✖➗

 

2、Q查詢

# Q查詢
# 或的關系
res = models.Product.objects.filter(Q(price=188.88), Q(name='帽子爆款')) # and
res = models.Product.objects.filter(Q(price=188.88)|Q(name='帽子爆款'))  # or

# 價格是188.88或者name不是帽子爆款的; 這里not用 ~表示
res = models.Product.objects.filter(Q(price=188.88) | ~ Q(name='帽子爆款'))  # not
print(res)

# 混合使用
# 名字不是帽子爆款,並且價格是188.88的
# 需要注意的是Q對象必須放在普通的過濾條件前面
res = models.Product.objects.filter(~Q(name='帽子爆款'), price=188.88)
print(res)


# 當條件是字符串時
q = Q()
q.connector = 'or'   # 通過這個參數可以將Q對象默認的and關系變成or
q.children.append(('price', 188.88))   # children和append是兩個方法,就是將條件加進去(price=188.88)
q.children.append(('name', '褲子爆款'))
res = models.Product.objects.filter(q)   # 原先Q對象查詢默認是and,但是現在改為or了,也就是在Product表中price=188.88或者name=褲子爆款的所有數據;
print(res)

 

3、ORM事務

# 事務
from django.db import transaction
with transaction.atomic():
    # 在with代碼塊寫實務操作
    models.Product.objects.filter(id=1).update(kucun=F('kucun')-1)
    models.Product.objects.filter(id=1).update(kucun=F('maichu') + 1)

# 出了with就可以寫其他代碼邏輯
print("123")

 

4、自定義ORM字段

#models.py

class MyCharField(models.Field):
    """
    自定義的char類型的字段類
    """
    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super().__init__(max_length=max_length, *args, **kwargs)

    """
    限定生成數據庫表的字段類型為char,長度為max_length指定的值
    """
    def db_type(self, connection):
        return 'char(%s)' %self.max_length


#接着就可以使用了
class Product(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    maichu = models.IntegerField()
    kucun = models.IntegerField()
    info = MyCharField(max_length=32, null=True)

 

5、only與defer

only

# only幫我們拿到一個對象
res = models.Product.objects.only('name')
# 結果:<QuerySet [<Product: Product object>, <Product: Product object>, <Product: Product object>]>
for i in res:
    # 如果這個對象在only中,走一次數據庫就可以全部拿到
    print(i.name)
    # 如果這個對象不在only中,也可以查,但是要反復走數據庫
    print(i.price)

 

defer

# 簡單來說defer的作用是與only是相反的

# defer幫我們拿到一個對象,
res = models.Product.objects.defer('name')
# 結果:<QuerySet [<Product: Product object>, <Product: Product object>, <Product: Product object>]>
for i in res:
    # 如果這個對象不在only中,走一次數據庫就可以全部拿到
    print(i.name)
    # 如果這個對象在only中,也可以查,但是要反復走數據庫
    print(i.price)

 

6、choices

# choices可以用在有固定某些選擇的地方,用數字來對應實際的選項,在數據庫中存儲的是數字,查詢的時候可以再把數字轉為實際的值;

# 比如我們在表中存儲人的性別時,一般也就分為:’男‘、‘女’、‘其他’這幾類,這時就可以用到choices功能了;

#models.py
class Product(models.Model):
    name = models.CharField(max_length=32)

    # 括號中是一個元組,寫的就是數字與實際值的對應關系
    choices = ((1, ''), (2, ''), (3, '其他'))
    gender = models.IntegerField(choices=choices, default=2)  # default=2:默認值是女


# 然后:
python3 manage.py makemigrations  
python3 manage.py migrate

 

數據庫中的存儲情況,我這里還是用前面的Product表舉的例子:

image

 

查詢:

# tests.py

# choices
res = models.Product.objects.filter(id=1).first()
print(res.gender)    # 獲取編號;結果:2
print(res.get_gender_display())    # 獲取編號對應的實際值;結果:女;get_xxx_display()是固定寫法

 

其他適用場景:

# choices使用場景還還是很多的
# 如上面的性別,其他的還有學歷(本科,專科...)、成績級別(A+,A,B,C...)、上班打卡(已簽到,遲到,早退...)
# 等等......


免責聲明!

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



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