【问题标题】:Django filter filter with listsDjango过滤器过滤器与列表
【发布时间】:2015-11-18 13:26:01
【问题描述】:

所以,我有这个模型:

class Product(models.Model):
    colors = models.TextField(max_length=150,default = 'blue,green,blue')

例如,我想用颜色列表对其进行过滤。
关于我该怎么做的任何想法?
colors = ["blue","green"]
我需要这样的东西。

products = Product.objects.filter(colors__icontains = colors)

任何关于如何修改模型以进行过滤的帮助或建议都将不胜感激。

【问题讨论】:

  • 顺便说一句,您可能希望使用choices 属性来选择可能的颜色(如果您选择不使用单独的颜色模型)
  • 这将使我能够多选颜色?
  • 我认为制作新的模型颜色并使用 manytomanyfield 将是正确的选择。我仍在努力让它工作。谢谢

标签: python django django-queryset


【解决方案1】:

由于您将颜色存储为纯文本而不使用相关模型,因此您无法使用所需的过滤器类型。

正确的做法是使用ManyToManyField:一种颜色可以有多种产品,一种产品可以有多种颜色:

class Color(models.Model):
    name = models.CharField(max_length=255)

class Product(models.Model):
    colors = models.ManyToManyField(Color, related_name='colors')

然后,您可以像这样添加颜色:

blue = Color(name='blue')
blue.save()
red = Color(name='red')
red.save()
my_product = Product()
my_product.save()
my_product.colors.add(blue)

如果您想查询所有红色或蓝色的产品,只需:

Product.objects.filter(colors__in=[red, blue]) # Red and blue being Color instances

如果您想要所有红色和蓝色的产品,只需按照here 所述进行操作:

Product.objects.filter(colors=red).filter(colors=blue) # Red and blue being Color instances

像这样的链接过滤器不是特别方便,所以您可能需要一个自定义的QuerySet 来为您做这件事:

class AllManyToManyQuerySet(models.QuerySet):
    def filter_all_many_to_many(self, attribute, *args):
        qs = self
        for arg in args:
            qs = qs.filter(**{attribute: arg})
        return qs

class Product(models.Model):
    colors = models.ManyToManyField(Color, related_name='colors')
    objects = AllManyToManyQuerySet.as_manager()

并像这样使用它:

Product.objects.all().filter_all_many_to_many('colors', red, blue) # red and blue being color instances

另一种过滤方法是:

product_list = Product.objects.filter(reduce(operator.and_, [Q(colors__name=c) for c in colors]))

它未经测试,但它应该可以工作,如果你在其他地方需要它,你可以在其他类上使用查询集,让你的代码保持干净和干燥;)

【讨论】:

  • 对不起,我忘记在 QuerySet 类上添加解包了!
【解决方案2】:

你可以迭代它,在你需要数据之前什么都不会执行

products = Product.objects.all()
for color in colors:
    products = products.filter(colors__icontains=color)

【讨论】:

  • 任何想法是否可以在单行上制作? :)
  • @RusMine - 使用colors__in=colors 可能有效,但我没有测试过(认为它是错误的方式),失败了,你尝试过icontains 吗?
  • @RusMine - 不这么认为,但就其价值而言,我认为这 3 行在做什么很清楚,可能有一种方法可以在一行中构造一组过滤器,但是这会比这里的东西更令人困惑,这就是为什么我不想那样展示
  • 对我的问题来说是一个很好的答案,我赞成,但我不会接受它作为最终答案,因为我正在等待单行过滤器。稍后我将需要过滤性别、类别..等,我想将它放在一行:)
  • @RusMine - 当然不用担心,它应该是可能的,但它会非常难看,而且你什么也得不到。我所说的“什么都没有执行”是指 django 查询集是懒惰地完成的,因此在您需要数据之前不会真正查询数据库
【解决方案3】:

抱歉,我没有得到您需要的逻辑操作:ANDOR。但这没什么大不了的。这是一个单行:

from operator import or_, and_  # i'm not quite sure which one you actually need.
from django.db.models import Q

colors = ["blue","green"]
Product.objects.filter(reduce(or_, [Q(colors__icontains=c) for c in colors]))

但说到设计,我不能说有任何理由像这样存储这些值。如果您出于某种原因不想使用ManyToMany,请考虑ArrayField

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-01
    • 1970-01-01
    • 2021-04-29
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-03-27
    • 2014-01-02
    相关资源
    最近更新 更多