如何在Django查询中处理可变数量的参数

问题描述 投票:2回答:2

我当前的项目让我建立了一个页面,可以按类别过滤输出。默认情况下,这意味着您将获得项目的完整列表,但可以通过单击(多个或单个)复选框来缩小输出范围。这样做的想法是,如果您只想查看两个类别的结果,则可以选择这两个类别,然后仅查看这两个类别的项目。 (就像一个亚马逊页面,您可以在其中搜索项目但过滤结果)

这通过使用get方法的表单来完成。因此,该网址将类似于:

ip/?family=category_one&family=category_two

我的代码如下:

请注意,固件模型通过ManyToManyField与ProductModel相关,而ProductModel通过ForeignKey关系与Family相关

*型号

class Family(models.Model):
    family_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    slug = models.SlugField(null=False, unique=True)
    family_name = models.CharField(max_length=50, editable=True, unique=True)

class ProductModel(models.Model):
    model_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    model_number = models.CharField(max_length=25, editable=True, unique=True)
    family_id = models.ForeignKey(Family, on_delete=models.DO_NOTHING, editable=True, null=False, blank=False)

class Firmware(models.Model):
    firmware_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    version = models.CharField(max_length=50, help_text='The \'version number\' of the firmware',
                               editable=True)
    model_id = models.ManyToManyField(ProductModel, editable=True)

*查看:

class FirmwareListView(ListView):
    model = Firmware
    context_object_name = 'firmwares'
    qs = QuerySet()

    def get(self, request, *args, **kwargs):
        requested_families = request.GET.getlist("family")
        if requested_families:
            query = Q(model_id__family_id__family_name__iexact=requested_families[0])
            for f in range(1, len(requested_families)):
                query = query | Q(model_id__family_id__family_name__iexact=requested_families[f])
            self.qs = Firmware.objects.filter(query)
        else:
            self.qs = Firmware.objects.all()
        return super().get(request, *args, **kwargs)

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data()
        context['firmware_list'] = self.qs
        return context

这里最重要的部分是:

        requested_families = request.GET.getlist("family")
        if requested_families:
            query = Q(model_id__family_id__family_name__iexact=requested_families[0])
            for f in range(1, len(requested_families)):
                query = query | Q(model_id__family_id__family_name__iexact=requested_families[f])
            self.qs = Firmware.objects.filter(query)

此查询将起作用(因为它运行并返回结果,但结果是错误的。结果似乎好像它们忽略了[[exact要求,而只运行一个[[contains]]查询。换句话说, ,如果按类别foo进行过滤,则会得到foodfoo的结果。如果通过执行以下操作来运行查询:self.qs = Firmware.objects.filter(Q(model_id__family_id__family_name__iexact=requested_families[0]) | Q(model_id__family_id__family_name__iexact=requested_families[1]))

并且我选择两个类别,结果是完美的。当然,我无法在生产中使用上述方法,因为我永远不知道用户将选择多少个类别。
我看过这篇文章(Django query with variable number of filter arguments),并在那里尝试了所有建议,但没有运气。 

我相信问题是我试图从运行多对多字段然后再通过外键的模型中筛选字段。没有办法解决这个问题(至少我可以想到)

非常感谢提供的任何帮助。我对此有些困惑,但是必须有一种方法可以做到。目前,我唯一想到的方法是对每个术语执行单独的查询,然后在最后合并结果。

我当前的项目让我建立了一个页面,可以按类别过滤输出。默认情况下,您可以获得项目的完整列表,但可以通过单击(多个或一个...

django django-queryset
2个回答
0
投票

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.