我經常發現自己不止一次在我的Django應用程序中編寫了相同的條件。我通常會將它封裝在一個返回Django Q()對象的函數中,這樣我就可以在一個地方維護標準。從其他Q()對象構建Django Q()對象,但有關係跨越上下文
我會做這樣的事情在我的代碼:
def CurrentAgentAgreementCriteria(useraccountid):
'''Returns Q that finds agent agreements that gives the useraccountid account current delegated permissions.'''
AgentAccountMatch = Q(agent__account__id=useraccountid)
StartBeforeNow = Q(start__lte=timezone.now())
EndAfterNow = Q(end__gte=timezone.now())
NoEnd = Q(end=None)
# Now put the criteria together
AgentAgreementCriteria = AgentAccountMatch & StartBeforeNow & (NoEnd | EndAfterNow)
return AgentAgreementCriteria
這使得它,這樣我就不用想通過DB模式不止一次,我可以從這些組合的返回值功能建立更復雜的標準。到目前爲止效果很好,並且在數據庫模型更改時節省了我的時間。
當我開始將這些函數的標準結合起來時,我已經意識到Q()對象固有地與被調用的對象類型.filter()綁定在一起。這是我所期望的。
我偶爾會發現自己想從我的一個函數中使用Q()對象來構造另一個Q對象,該對象旨在過濾不同但相關的模型實例。
讓我們用一個簡單/人爲的例子來展示我的意思。 (這很簡單,通常這是不值得的開銷,但請記住,我在這裏使用一個簡單的例子來說明什麼是我的應用程序更復雜。)
說我有一個函數返回一個Q( )對象,找到所有Django的用戶,其用戶名與「A」開頭:
def UsernameStartsWithAaccount():
return Q(username__startswith='a')
說,我有一個相關的模型,該模型與設置,包括他們是否想要從我們的電子郵件用戶配置文件:
class UserProfile(models.Model):
account = models.OneToOneField(User, unique=True, related_name='azendalesappprofile')
emailMe = models.BooleanField(default=False)
說我想查找所有具有au的UserProfiles以'a'開頭的服務名稱,並希望用它們發送一些電子郵件通訊。我可以很容易地編寫用於後者的Q()對象:
wantsEmails = Q(emailMe=True)
但發現自己想要的東西,爲前者做這樣的事情:
startsWithA = Q(account=UsernameStartsWithAaccount())
# And then
UserProfile.objects.filter(startsWithA & wantsEmails)
不幸的是,不工作(它會在我嘗試它時生成無效的PSQL語法)。
換句話說,我正在尋找一條沿Q(account=Q(id=9))
的語法,它將返回與Q(account__id=9)
相同的結果。
所以,有幾個問題,從這個出現:
- 是否有使用Django Q上的語法()對象,可以讓你的「上下文」添加到他們,讓他們從模型交叉關係的界限,你正在運行.filter()?
- 如果不是,這在邏輯上是可能的嗎? (因爲我可以寫
Q(account__id=9)
當我想要做像Q(account=Q(id=9))
這樣的東西時好像是)。
我其實更喜歡'&'和'|'經營者表達標準。如果您使用描述性名稱命名較小的Q()變量,則幾乎可以大聲朗讀代碼並使其在英語中有意義。但它看起來像你必須使用字典'**'語法來創建字段名稱,就像你建議的那樣,我將採用你的解決方案的那部分。 (謝謝!) – Azendale