我想执行逻辑异或(XOR http://en.wikipedia.org/wiki/Exclusive_disjunction) on django.db.models.Q
对象,使用operator http://docs.python.org/2/library/operator.html模块将模型字段的选择限制为外键的子集。我在 Django 1.4.3 和 Python 2.7.2 中执行此操作。我有这样的事情:
import operator
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User, Group
def query_group_lkup(group_name):
return Q(user__user__groups__name__exact=group_name)
class Book(models.Model):
author = models.ForeignKey(
User,
verbose_name=_("Author"),
null=False,
default='',
related_name="%(app_label)s_%(class)s_author",
# This would have provide an exclusive OR on the selected group name for User
limit_choices_to=reduce(
operator.xor,
map(query_group_lkup, getattr(settings, 'AUTHORIZED_AUTHORS', ''))
)
AUTHORIZED_AUTHORS
是现有组名称的列表。
但这并没有奏效,因为Q
对象不支持^
运算符(仅|
and &
运营商从docs https://docs.djangoproject.com/en/1.4/topics/db/queries/#complex-lookups-with-q-objects)。来自堆栈跟踪的消息(部分)如下:
File "/home/moi/.virtualenvs/venv/lib/python2.7/site-packages/django/db/models/loading.py", line 64, in _populate
self.load_app(app_name, True)
File "/home/moi/.virtualenvs/venv/lib/python2.7/site-packages/django/db/models/loading.py", line 88, in load_app
models = import_module('.models', app_name)
File "/home/moi/.virtualenvs/venv/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/opt/dvpt/toto/apps/book/models.py", line 42, in <module>
class Book(models.Model):
File "/opt/dvpt/toto/apps/book/models.py", line 100, in Book
map(query_group_lkup, getattr(settings, 'AUTHORIZED_AUTHORS', ''))
TypeError: unsupported operand type(s) for ^: 'Q' and 'Q'
因此,受此启发answer https://stackoverflow.com/questions/8903128/python-list-to-bitwise-operations我尝试为我的特定查找实现异或。它并不是很灵活,因为查找是硬编码的(我需要使用kwargs
在论据中query_xor
例如...)。我最终做了这样的事情:
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.db.models.query import EmptyQuerySet
from django.contrib.auth.models import User, Group
def query_xor_group(names_group):
"""Get a XOR of the queries that match the group names in names_group."""
if not len(names_group):
return EmptyQuerySet()
elif len(names_group) == 1:
return Q(user__user__groups__name__exact=names_group[0])
q_chain_or = Q(user__user__groups__name__exact=names_group[0])
q_chain_and = Q(user__user__groups__name__exact=names_group[0])
for name in names_group[1:]:
query = Q(user__user__groups__name__exact=name)
q_chain_or |= query
q_chain_and &= query
return q_chain_or & ~q_chain_and
class Book(models.Model):
author = models.ForeignKey(
User,
verbose_name=_("author"),
null=False,
default='',
related_name="%(app_label)s_%(class)s_author",
# This provides an exclusive OR on the SELECT group name for User
limit_choices_to=query_xor_group(getattr(settings, 'AUTHORIZED_AUTHORS', ''))
)
它按照我想要的方式工作,但在我看来,我并不是Pythonic(尤其是query_xor_group
方法)。
是否有更好(更直接的方式)来做到这一点?
基本上,我的问题可以被剥夺limit_choices_to
部分并总结为:
如何对一组进行按位异或运算django.db.models.Q
以姜戈式的方式对象?