Django: Filter for get_foo_display in a Queryset
Asked Answered
L

4

16

I've been trying to filter a queryset on a simple model but with no luck so far.

Here is my model:

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()

And I would like to do something like:

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

But none of those above are working. How do you filter on a field that has a choices attribute? I thought the overridden __unicode__ would help but I guess I'm missing something.

Leanora answered 18/1, 2011 at 17:55 Comment(0)
D
28

You can't do this. filter works at the database level, and the database doesn't know anything about your long names. If you want to do filtering on a value, you need to store that value in the database.

An alternative is to translate the value back into the code, and filter on that:

country_reverse = dict((v, k) for k, v in COUNTRY_CHOICES)
Country.objects.filter(code=country_reverse['france'])
Dictate answered 18/1, 2011 at 18:3 Comment(3)
Thanks Daniel for your answer.Leanora
Isn't there something django can do about this to make it a bit easier. I thought this would be a common operationChopstick
The Choices class on django-model-utils can be useful in this way.Apposition
G
3

You can use 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)

And make a query:

Country.objects.filter(code=Country.COUNTRY_CHOICES.france)
Gouveia answered 6/12, 2017 at 17:11 Comment(0)
Z
1

You can swap values in constructor:

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']
Ziagos answered 27/5, 2015 at 16:45 Comment(0)
H
0

Inspired from this answer, I did the following:

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)
Hoeg answered 20/11, 2017 at 19:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.