【发布时间】: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 我将得到 food 和 foo 的结果。如果我运行查询通过执行以下操作:
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) 并尝试了那里的所有建议,但没有成功。
我认为问题是我试图从一个模型中过滤一个字段,该模型通过多对多字段然后是外键。没有办法解决这个问题(至少我能想到)
非常感谢您提供的任何帮助。我有点坚持这个,但必须有办法做到这一点。目前我能想到的唯一方法是对每个术语执行单独的查询,然后在最后合并结果。
【问题讨论】: