Django:在Queryset中为get_foo_display过滤器进行筛选

16

我一直在尝试在一个简单模型上过滤查询集,但是到目前为止还没有成功。

这是我的模型:

class Country(models.Model):
    COUNTRY_CHOICES = (
        ('FR', _(u'France')),
        ('VE', _(u'Venezuela')),
    )

    code = models.CharField(max_length=2, choices=COUNTRY_CHOICES)

    def __unicode__(self):
        return self.get_code_display()

我想要做类似这样的事情:

Country.objects.filter(get_code_display__icontains="france")
Country.objects.filter(code__display__icontains="france")
Country.objects.filter(get_code_display__icontains="france")

但是上述方法都没有起作用,如何筛选一个具有choices属性的字段?我认为重载 __unicode__ 方法会有帮助,但我觉得我漏掉了某些东西。

4个回答

28

你不能这样做。 filter 在数据库层面工作,而数据库并不知道你的长名称。如果你想要对一个值进行过滤,你需要将该值存储在数据库中。

另一种选择是将该值转换回代码,然后在其上进行过滤:

country_reverse = dict((v, k) for k, v in COUNTRY_CHOICES)
Country.objects.filter(code=country_reverse['france'])

感谢Daniel的回答。 - jtheoof
10
有没有 Django 可以做些什么来使这个过程更容易一些?我认为这应该是一个常见的操作。 - Robert Johnstone
Choices类在django-model-utils中可以以这种方式使用。 - caesarsol

3
您可以使用Choices
from model_utils import Choices

class Country(models.Model):
    COUNTRY_CHOICES = Choices((
        ('FR', _(u'France')),
        ('VE', _(u'Venezuela')),
    ))

    code = models.CharField(max_length=2, choices=COUNTRY_CHOICES)

并发出一个查询:

Country.objects.filter(code=Country.COUNTRY_CHOICES.france)

1
您可以在构造函数中交换值:
class PostFilter(django_filters.FilterSet):

    def __init__(self, data=None, queryset=None, prefix=None, strict=None):
        data = dict(data)
        if data.get('type'):
            data['type'] = Post.get_type_id(data['type'][0])

        super(PostFilter, self).__init__(data, queryset, prefix, strict)

    class Meta:
        model = Post
        fields = ['type']

0
受到这个答案的启发,我做了以下操作:
search_for = 'abc'

results = (
    [
        x for x, y in enumerate(COUNTRY_CHOICES, start=1) 
        if search_for.lower() in y[1].lower()
    ]
)

Country.objects.filter(code__in=results)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接