blueFast
blueFast

Reputation: 44331

Filter on a field with choices

I have this field:

operation = models.CharField(max_length=10, choices=OPERATIONS)

Having this filter works:

class OperationFilter(django_filters.Filter):

    def filter(self, qs, value):
        try:
            qs = qs.filter(operation=value.upper())
        except:
            pass
        return qs

With url:

/api/v1/operation/?operation=CREATE

But having the default filter (without an extra OperationFilter) fails with:

{
    "operation": [
        "Select a valid choice. %(value)s is not one of the available choices."
    ]
}

Why is a filter on a field with choices failing?

For other, non-choice fields, default filters are working fine:

/api/v1/operation/?recipient=recipient-19

EDIT

The OPERATIONS:

from enum import Enum

def enum_as_choices(enum_class):
    """From an enum class, generate choices for a django field"""
    return ((entry, entry.value) for entry in enum_class)

class OperationType(Enum):
    CREATE = 'CREATE'
    STATUS = 'STATUS'
    EXPAND = 'EXPAND'
    DELETE = 'DELETE'

OPERATIONS = enum_as_choices(OperationType)

Upvotes: 0

Views: 3285

Answers (3)

Gabriel Muj
Gabriel Muj

Reputation: 3805

You are using django_filters package, I suggest reading docs, since you already have support for this

https://django-filter.readthedocs.io/en/master/ref/filters.html#choicefilter

Just point out your choices to the value suggested by the other answers (or check the example in docs)

Upvotes: 2

Mohsen Mahmoodi
Mohsen Mahmoodi

Reputation: 357

The choices you written would be converted to this pythonic representation:

(
    ('OperationType.CREATE', 'CREATE'), 
    ('OperationType.STATUS', 'STATUS'), 
    ('OperationType.EXPAND', 'EXPAND'), 
    ('OperationType.DELETE', 'DELETE')
)

As you can see the actual values stored in your operation field (in DB) are 'OperationType.CREATE', etc. So you should change your choices to normal constant choices or you should filter by something like 'OperationType.CREATE' which is not a good option IMO.

also you can change your enum_as_choices method like this:

def enum_as_choices(enum_class):
    """From an enum class, generate choices for a django field"""
    return ((entry.name, entry.value) for entry in enum_class)

Upvotes: 1

Daniel Holmes
Daniel Holmes

Reputation: 2002

You haven't defined a blank/default choice in your OPERATIONS. To do so, add something like this:

OPERATIONS = (
    ('', 'NONE'),
    # the rest of your choices here...
)

But you would also need to update your model to be:

operation = models.CharField(max_length=10, choices=OPERATIONS, default='NONE')

Upvotes: 0

Related Questions