1. 程式人生 > >Python-模型類-F()物件和Q()物件詳解

Python-模型類-F()物件和Q()物件詳解

定義模型
from django.db import models
from django.db.models import F, Q

class Publisher(models.Model):
    """出版社"""
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    country = models.CharField(max_length=50)

    def
__unicode__(self):
return self.name class Author(models.Model): """作家""" first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) class
Book(models.Model):
"""書""" title = models.CharField(max_length=100) publisher = models.ForeignKey(Publisher) price = models.IntegerField(default=0) def __unicode__(self): return self.title
一、F物件:
需求:
  • 當一般的查詢語句已經無法滿足我們的需求時,Django為我們提供了F和Q複雜查詢語句。比如在我定義的這個模型類中, 書的價格飛漲,從以前的20元,漲到了21元。我們應該怎麼辦?這個時候F物件是最佳首選。
>>> Book.objects.all().first().price  # 簡單的查詢了 資料庫中書的價格
>>> # 返回的是 20 
>>> # 下面我想將價格飛速的上漲到21元
>>> Book.objects.update(price=F("price")+1)
>>> Book.objects.all().first().price
>>> 返回的結果是 21 
>>> # 這本書的價格又發生了改變,降到了 6塊錢
>>> Book.objects.update(price=F("price")-15)
(0.003) UPDATE `apps_book` SET `price` = (`apps_book`.`price` - 15); args=(15,)
>>> # 返回的結果是6元
  • 接下來讓我們檢視一下SQL語句:
(0.003) UPDATE `apps_book` SET `price` = (`apps_book`.`price` + 1); args=(1,)
  • F查詢專門對物件中某劣值的操作,不可以使用雙下劃線("__")
二、Q物件:
  • Q查詢可以組合使用“&”,“|” 操作符,當一個操作符是用於兩個Q的物件,它產生一個新的Q物件,Q物件可以用 “~” 操作符放在前面表示否定,也可允許否定與不否定形式的組合。Q物件可以與關鍵字引數查詢一起使用,不過一定要把Q物件放在關鍵字引數查詢的前面
    • 接下來filter()裡面一個Q物件的情況下:
from django.db.models import Q
# 使用Q物件,返回的是QuerySet通過[0]下標來獲取值(一般情況下不使用下標的方式,獲取不到會報錯)
>>> Book.objects.filter(Q(id=3))[0]
(0.000) SELECT `apps_book`.`id`, `apps_book`.`title`, `apps_book`.`publisher_id`, `apps_book`.`price` FROM `apps_book` WHERE `apps_book`.`id` = 3 LIMIT 1; args=(3,)
<Book: cow>
# 返回QuerySet最好使用first()來獲取第一個物件而不用下標的方式[0]
>>> Book.objects.filter(Q(id=3)).first()
(0.000) SELECT `apps_book`.`id`, `apps_book`.`title`, `apps_book`.`publisher_id`, `apps_book`.`price` FROM `apps_book` WHERE `apps_book`.`id` = 3 ORDER BY `apps_book`.`id` ASC LIMIT
 1; args=(3,)
<Book: cow>
* 接下來filter()裡面二個Q物件的情況下:
# 看到了 | 是代表或的意思 只要一個條件滿足就會返回資料;顯然資料庫裡面title欄位沒有jave,所以返回的是id=2的物件
>>> Book.objects.filter(Q(id=2) | Q(title="java")).first()
(0.001) SELECT `apps_book`.`id`, `apps_book`.`title`, `apps_book`.`publisher_id`, `apps_book`.`price` FROM `apps_book` WHERE (`apps_book`.`id` = 2 OR `apps_book`.`title` = 'jave') O
RDER BY `apps_book`.`id` ASC LIMIT 1; args=(2, 'jave')
<Book: python>
# 我們在來做一個比較:
# 資料庫裡面沒有id=4的物件,正好title的欄位裡面有"python" 所以返回的是python對應的物件
>>> Book.objects.filter(Q(id=4)|Q(title="python")).first()
(0.000) SELECT `apps_book`.`id`, `apps_book`.`title`, `apps_book`.`publisher_id`, `apps_book`.`price` FROM `apps_book` WHERE (`apps_book`.`id` = 4 OR `apps_book`.`title` = 'python')
 ORDER BY `apps_book`.`id` ASC LIMIT 1; args=(4, 'python')
<Book: python>
# 接下來查詢一個複雜一些的:價格大於等於6元的,或者id大於等於1的物件
>>> Book.objects.filter(Q(price__gte=6)|Q(id__gt=1)).first()
(0.001) SELECT `apps_book`.`id`, `apps_book`.`title`, `apps_book`.`publisher_id`, `apps_book`.`price` FROM `apps_book` WHERE (`apps_book`.`price` >= 6 OR `apps_book`.`id` > 1) ORDER
 BY `apps_book`.`id` ASC LIMIT 1; args=(6, 1)
<Book: python>
  • 接下來告訴大家~Q()的玩法
# ~Q:就是代表非的意思
>>> Book.objects.filter(Q(price__gte=6) | ~Q(id__gt=1)).first()
(0.001) SELECT `apps_book`.`id`, `apps_book`.`title`, `apps_book`.`publisher_id`, `apps_book`.`price` FROM `apps_book` WHERE (`apps_book`.`price` >= 6 OR `apps_book`.`id` > 1) ORDER
 BY `apps_book`.`id` ASC LIMIT 1; args=(6, 1)
<Book: python>

其實預設的情況下filter()裡面每個欄位的連線都是& ,我們使用Q物件通常都是讓它變成|,來進行查詢
* 接下來我們來一個更復雜的Q物件查詢:

from django.db.models import Q

query = Q()
q1 = Q()
q1.connector = "AND"  # 連線的條件是AND 代表就是& 
q1.children.append(("email", "[email protected]")) # email代表的是資料庫的欄位
q1.children.append(("password", "666"))
 # 等同於:email="[email protected]" & password="666"
q2 = Q()
q2.connector = "AND"  # 同樣q2物件連線條件也是AND 
q2.children.append(("username", "fe_cow")) # 同樣資料庫裡username欄位
q2.children.append(("password", "fe_cow666"))
 # 等同於:username="fe_cow" & password="fe_cow666"
query.add(q1, "OR") 
query.add(q2, "OR")
 # query目前裡面的符合條件結果就是: (email="[email protected]" & password="666") |  (username="fe_cow" & password="fe_cow666")
userinfo_obj = models.UserInfo.objects.filter(query).first()

Q物件例項化來然後增加各個條件之間的關係,而且這種寫法用在你不知道使用者到底傳入了多少個引數的時候很方便