对具有两倍相同对象的动态查询集进行django过滤

时间:2014-11-13 23:00:43

标签: django dynamic filtering django-queryset

我正在尝试按com_proc变量进行过滤,但它不起作用... 这里的复杂性是过滤器可以多次包含 同一个对象。这是我的代码:

class Act(models.Model):
    com_proc=models.CharField(max_length=100, blank=True, null=True, default=None)
    cs_1=models.ForeignKey(CodeSect, related_name='code_sect_1', blank=True, null=True, default=None)
    cs_2=models.ForeignKey(CodeSect, related_name='code_sect_2', blank=True, null=True, default=None)
    cs_3=models.ForeignKey(CodeSect, related_name='code_sect_3', blank=True, null=True, default=None)

class ActIds(models.Model):
    propos_origine=models.CharField(max_length=4, blank=True, null=True, default=None)
    act=models.ForeignKey(Act)


qs_acts=ActIds.objects.none()
len(qs_acts)
for act in ActIds.objects.all():
    #loop over each cs variable
    for nb in range(1,4):
        code_sect=getattr(act.act, "cs_"+str(nb))
        if code_sect is not None:
            qs_acts._result_cache.append(act)
print "qs_acts"
for act in qs_acts:
    print act.pk, act.act.com_proc, act.propos_origine

我使用动态queryset_result_cache,因为每个对象最多可以在过滤器中出现三次(每个cs变量一次)。我不知道如何使用正常过滤重现它。

输出:

9429 Oral procedure COM
9429 Oral procedure COM
9697 Written procedure COM
12352 Written procedure COM
12362 Oral procedure COM

代码:

...
print filter_vars_periods

输出:

{'act__com_proc': 'Written procedure', 'propos_origine': 'COM', 'act__adopt_conseil__gte': datetime.date(2009, 12, 1), 'act__adopt_conseil__lte': datetime.date(2013, 12, 31)}

代码:

temp_filter=qs_acts.filter(**filter_vars_periods)
for act in temp_filter:
    print act.pk, act.act.com_proc, act.propos_origine

输出:

9429 Oral procedure COM
9429 Oral procedure COM
9697 Written procedure COM
12352 Written procedure COM
12362 Oral procedure COM

你可以看到com_proc="Written procedure"的过滤不起作用,我在最后得到了相同的查询集。为什么呢?

修改

我想我知道为什么两个连续的过滤不能给出预期的输出: Chaining multiple filter() in Django, is this a bug? 据说使用两个过滤器不等同于逻辑AND,而是等同于逻辑OR。这可能是我的第二个过滤器没有过滤任何东西的原因...... 无论如何,我仍然不知道如何解决我的问题:(。

1 个答案:

答案 0 :(得分:0)

我认为不可能使用多次存储相同对象的查询集。 相反,我使用列表

class Act(models.Model):
    com_proc=models.CharField(max_length=100, blank=True, null=True, default=None)
    cs_1=models.ForeignKey(CodeSect, related_name='code_sect_1', blank=True, null=True, default=None)
    cs_2=models.ForeignKey(CodeSect, related_name='code_sect_2', blank=True, null=True, default=None)
    cs_3=models.ForeignKey(CodeSect, related_name='code_sect_3', blank=True, null=True, default=None)

class ActIds(models.Model):
    propos_origine=models.CharField(max_length=4, blank=True, null=True, default=None)
    act=models.ForeignKey(Act)


qs_acts=[]
for act in ActIds.objects.all():
    #loop over each cs variable
    for nb in range(1,4):
        code_sect=getattr(act.act, "cs_"+str(nb))
        if code_sect is not None:
            qs_acts.append(act)

然后问题是我不能再做以下事了:

temp_filter=qs_acts.filter(**filter_vars).exclude(**exclude_vars)

相反,我创建了一个翻译django语法的函数:

def filter_exclude_list(list_acts, filter_vars={}, exclude_vars={}):
    list_acts_new=[]
    for act in list_acts:
        ok=True
        for key, value in filter_vars.iteritems():
            #related object: "act__validated_attendance":1
            if key[:5]=="act__":
                key=key[5:]
                instance=act.act
            else:
                instance=act
            #greater than or equal: "nb_point_a__gte": 1
            if key[-5:]=="__gte":
                if getattr(instance, key[:-5])<value:
                    ok=False
                    break
            #"com_amdt_tabled__isnull": False
            elif key[-8:]=="__isnull":
                if getattr(instance, key[:-8]) is None:
                    ok=False
                    break
            #equal to: "nb_point_a": 1
            elif getattr(instance, key) != value:
                ok=False
                break

        if ok:
            for key, value in exclude_vars.iteritems():
                #"adopt_cs_abs": None
                if key=="adopt_cs_abs" and value is None:
                    if not getattr(instance, key).exists():
                        ok=False
                        break
                #different from: "nb_point_a": 1
                elif getattr(instance, key) == value:
                    ok=False
                    break

            if ok:
                list_acts_new.append(act)

    return list_acts_new

然后我可以做:

qs_acts_new=filter_exclude_list(qs_acts, filter_vars=filter_vars, exclude_vars=exclude_vars)

这有效,但我发布这个希望有人有一个更好,更简洁的解决方案:)。