【问题标题】:how to handle a variable number of arguments in django query如何在 django 查询中处理可变数量的参数
【发布时间】:2020-05-31 02:05:22
【问题描述】:

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

这通过使用 get 方法的表单来工作。所以网址看起来像:

ip/?family=category_one&family=category_two

我的代码如下:

请注意,Firmware 模型通过 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 em> 查询。换句话说,如果我按类别过滤 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


    【解决方案1】:

    经过一番努力,终于搞定了。好吧,我造成了我自己的问题。首先,我通过另一种方法传递我的查询结果(我在原始问题中没有提到它,因为我认为它无关紧要)这改变了查询。

    第二种方法以独特的方式对输出进行排序。当我开始仔细研究该方法时,我注意到查询集在其中突然发生了变化。我找到了我犯错的地方,瞧!现在可以正常使用了。

    底线是使用上述方法创建可变数量的查询参数的方法(并在下面重新显示)工作完美。

    要在 Django 中创建可变数量的查询参数,您可以使用:

    class ViewName():
        qs = QuerySet()
    
        def get(self, request, *args, **kwargs):
            get_queries = request.GET.getlist('named_get')
            if get_queries:
                query = Q(query_type=get_queries[0])
                    for t in range(1, len(filtered_types)):
                        query = query | Q(query_type=get_queries[t]) #obviously if you need an and here just substitute in & where | currently is
                Model.objects.filter(query)
    

    【讨论】:

      【解决方案2】:

      我不得不做类似的事情。我最终使用了一个将 .exclude() 链接到未选中的查询集。我在表单中使用了一些 javascript 来传递正确的(我不想要的)值。

      【讨论】:

      • 嗯,有趣的解决方案。谢谢。我想我将使用不同的过滤系统。这不是按家庭过滤,而是按 ProductModel 模型过滤。
      猜你喜欢
      • 2018-03-24
      • 2011-04-08
      • 1970-01-01
      • 1970-01-01
      • 2014-07-08
      • 1970-01-01
      • 2018-06-16
      • 1970-01-01
      • 2012-03-28
      相关资源
      最近更新 更多