我经常发现自己不止一次在我的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