使用Django 1.8
我正在尝试筛选是否仅填充了所选字段中的一个的模型。如果我有这样的模型,我希望能够按如下所示对其进行过滤。
class MyModel(models.Model):
field_a = models.IntegerField(null=True)
field_b = models.IntegerField(null=True)
field_c = models.IntegerField(null=True)
field_d = models.IntegerField(null=True)
(field_a__isnull=False, field_b__isnull=True, field_c__isnull=True, field_d__isnull=True)
OR
(field_a__isnull=True, field_b__isnull=False, field_c__isnull=True, field_d__isnull=True)
OR
(field_a__isnull=True, field_b__isnull=True, field_c__isnull=False, field_d__isnull=True)
OR
(field_a__isnull=True, field_b__isnull=True, field_c__isnull=True, field_d__isnull=False)
因此,查询集应返回仅填充了模型中的一个字段且其余字段为null的所有对象。有没有办法通过Django查询来实现这一目标?
答案 0 :(得分:1)
我能够使用Q动态构建它
fields = ['field_a', 'field_b', 'field_c', 'field_d']
q_query = reduce(operator.or_, (
(reduce(operator.and_, (
eval('Q({}__isnull={})'.format(field, False if fields[i] == field else True))
for field in fields
)))
for i in range(len(fields))
))
MyModel.objects.filter(q_query)
这将构建一个Q对象,该对象具有与OR过滤器嵌套的AND过滤器并对其进行查询
<Q: (
OR: (
AND: ('field_a__isnull', False), ('field_b__isnull', True), ('field_c__isnull', True), ('field_d__isnull', True)
), (
AND: ('field_a__isnull', True), ('field_b__isnull', False), ('field_c__isnull', True), ('field_d__isnull', True)
), (
AND: ('field_a__isnull', True), ('field_b__isnull', True), ('field_c__isnull', False), ('field_d__isnull', True)
), (
AND: ('field_a__isnull', True), ('field_b__isnull', True), ('field_c__isnull', True), ('field_d__isnull', False)
)
)>
答案 1 :(得分:0)
如果您需要快速而又肮脏的解决方案,则可以尝试向模型中添加属性,然后使用该属性来查询模型中是否只有一个填充字段。
class MyModel(models.Model):
field_a = models.IntegerField(null=True)
field_b = models.IntegerField(null=True)
field_c = models.IntegerField(null=True)
field_d = models.IntegerField(null=True)
@property
def populated_field_count(self):
fields = [self.field_a, self.field_b, self.field_c, self.field_d]
return len([f for f in fields if f != None])
objects_with_one_field = [obj for obj in MyModel.objects.all() if obj.populated_field_count == 1)]
请注意,populated_field_count属性不能在Django查询中使用,这意味着它无法在数据库级别运行,这对性能造成了打击。
# THIS WILL NOT WORK IF USING OPTION ONE
objs = MyModel.objects.filter(populated_field_count=1)
编辑:作为选项二,如果您需要通过查询完成此操作,则可以使用Django Q进行高级查询。该选项的答案已经给出。
作为选择三,如果您不想使用Django Q,则可以将populated_field_count添加为Model的IntegerField属性。然后覆盖保存功能,以计算每次保存时填充的字段数。然后,您可以使用以下方式进行查询:
MyModel.objects.filter(populated_field_count=1)