Mar*_*eux 8 python django django-queryset django-q
我想在django.db.models.Q对象上执行逻辑异或(XOR),使用运算符模块将模型字段的选择限制为外键的子集.我在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', ''))
)
Run Code Online (Sandbox Code Playgroud)
AUTHORIZED_AUTHORS 是现有组名称的列表.
但这不起作用,因为Q对象不支持^运算符(仅来自文档的 |和&运算符).来自stacktrace的消息(部分)如下:
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'
Run Code Online (Sandbox Code Playgroud)
因此,受此答案的启发,我试图为我的特定查找实现XOR.它不是很灵活,因为查找是硬编码的(我需要在query_xor的参数中使用kwargs,例如......).我最终做了这样的事情:
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', ''))
)
Run Code Online (Sandbox Code Playgroud)
它按我的意思工作,但我觉得我不是pythonic(尤其是query_xor_group方法).这样做会有更好的(更直接的方式)吗?
基本上,我的问题可以被剥夺limit_choices_to部分,并总结为:
如何以Djangonic方式对一组django.db.models.Q对象进行按位异或?
Ben*_*hon 13
Django 4.1添加了对 XOR 的支持:
Q现在可以使用^异或 (XOR) 运算符来组合对象和查询集。XORMariaDB 和 MySQL 本身支持。对于不支持的数据库XOR,查询将转换为使用AND、OR和 的等效查询NOT。
这意味着您现在无需猴子修补即可编写Foobar.objects.filter(Q(blah=1) ^ Q(bar=2))。
九年的等待是值得的,不是吗?
Dan*_*cci 12
您可以__xor__()向使用和/或/不执行XOR逻辑的Q 添加方法.
from django.db.models import Q
class QQ:
def __xor__(self, other):
not_self = self.clone()
not_other = other.clone()
not_self.negate()
not_other.negate()
x = self & not_other
y = not_self & other
return x | y
Q.__bases__ += (QQ, )
Run Code Online (Sandbox Code Playgroud)
这样做后,我能够Q(...) ^ Q(...)在filter()通话.
Foobar.objects.filter(Q(blah=1) ^ Q(bar=2))
Run Code Online (Sandbox Code Playgroud)
这意味着原始尝试不再抛出不受支持的操作数异常.
limit_choices_to=reduce(
operator.xor,
map(query_group_lkup, getattr(settings, 'AUTHORIZED_AUTHORS', ''))
)
Run Code Online (Sandbox Code Playgroud)
经测试,在Django 1.6.1上Python 2.7.5
| 归档时间: |
|
| 查看次数: |
2507 次 |
| 最近记录: |