I have following filterset for some model:
class MyModel(models.Model):
STATUS_ACTIVE = 0
STATUS_DONE = 1
STATUSES = (
(STATUS_ACTIVE, 'Active'),
(STATUS_DONE, 'Done'),
)
status = models.IntegerField(choices=STATUSES, default=STATUS_ACTIVE)
class ModelFilter(FilterSet):
status = ChoiceFilter(choices=MyModel.STATUSES)
class Meta:
model = MyModel
fields = (
'status',
)
When I make request to some API, i should use status as number - /app/model?status=0
.
How to make alias for it, so that i can use /app/model?status=active
instead of number, without changing model?
At th end I found source code inside the library and created this solution:
class AliasesChoiceField(ChoiceField):
def valid_value(self, value):
for _, v in self.choices:
if value == v or str(value) == str(v):
return True
return False
class AliasesChoiceFilter(ChoiceFilter):
field_class = AliasesChoiceField
def filter(self, qs, value):
for val, alias in self.extra['choices']:
if value == alias:
return super(AliasesChoiceFilter, self).filter(qs, val)
return super(AliasesChoiceFilter, self).filter(qs, value)
At AliasesChoiceField.valid_value()
i just copied the base method with simple changes to validate value correctly.
AliasesChoiceFilter
use field_class
for validation, so i just replace it with ChoiceFilter
, and change filter()
method to right mapping of my choice parameters.
Finally my model looks like this
class ModelFilter(FilterSet):
STATUSES = (
(MyModel.STATUS_ACTIVE, 'active'),
(MyModel.STATUS_DONE, 'done')
)
status = AliasesChoiceFilter(choices=STATUSES)
And API route /app/model?status=active
works correctly, setting right status on filtering.
But! This solution wouldn't work for Django Admin, or through web api interface, because it will offer real values, and will try to pass 0
instead of active