在 Django 3 中,如何基于条件数组构建 AND 查询?

In Django 3, how do I build an AND query based on an array of conditions?

我正在使用 Python 3.8 和 Django 3。我有以下模型 ...

class Coop(models.Model):
    objects = CoopManager()
    name = models.CharField(max_length=250, null=False)
    types = models.ManyToManyField(CoopType, blank=False)
    addresses = models.ManyToManyField(Address)
    enabled = models.BooleanField(default=True, null=False)
    phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
    email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
    web_site = models.TextField()

我想构建一个高级搜索,我可以根据是否提供这些属性来搜索一个或多个属性。我有

class CoopManager(models.Manager):
    def find(self, name, type, enabled):
        if name:
            qset = Coop.objects.filter(name=name) 
        if type:
            qset = Coop.objects.filter(type__name=type) 
        if enabled:
            qset = Coop.objects.filter(enabled=enabled)        

        return qset

但是上面是有缺陷的,因为它只会搜索一个属性。如何创建条件数组并将它们传递给我的查询?例如,如果提供了“enabled”和“name”,那么查询应该只搜索这两个东西。如果提供了“类型”和“名称”,我应该只搜索这两个东西。

您可以链接过滤器,从而在下一次过滤中使用可能已经被过滤的qset:

class CoopManager(models.Manager):
    def find(self, name<b>=None</b>, type<b>=None</b>, enabled<b>=None</b>):
        <b>qset</b> = Coop.objects.all()
        if name:
            qset = <b>qset</b>.filter(name=name) 
        if type:
            qset = <b>qset</b>.filter(type__name=type) 
        if enabled:
            qset = <b>qset</b>.filter(enabled=enabled)        
        return qset

或者更方便,你可以做一个辅助函数:

def filter_qs_without_none(qs, **kwargs):
    return qs.filter(<b>**{k: v for k, v in kwargs.items() if v is not None}</b>)

然后你可以过滤:

class CoopManager(models.Manager):
    def find(self, name<b>=None</b>, type<b>=None</b>, enabled<b>=None</b>):
        return <b>filter_qs_without_none(</b>
            Coop.objects.all(),
            name=name,
            type__name=type,
            enabled=enabled
        <b>)</b>