Создать псевдоним для фильтрации ChoiceField в django -фильтрах - PullRequest
2 голосов
/ 21 апреля 2020

У меня есть следующий набор фильтров для некоторой модели:

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',
        )

Когда я делаю запрос к некоторому API, я должен использовать статус как число - /app/model?status=0.

Как сделать псевдоним для так, чтобы я мог использовать /app/model?status=active вместо числа, не меняя модель?

1 Ответ

0 голосов
/ 21 апреля 2020

В конце я нашел исходный код внутри библиотеки и создал это решение:

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)

На AliasesChoiceField.valid_value() я просто скопировал базовый метод с простыми изменениями, чтобы правильно проверить значение.

AliasesChoiceFilter используйте field_class для проверки, поэтому я просто заменяю его на ChoiceFilter и меняю filter() метод на правильное сопоставление параметров моего выбора.

Наконец моя модель выглядит следующим образом

class ModelFilter(FilterSet):
    STATUSES = (
        (MyModel.STATUS_ACTIVE, 'active'),
        (MyModel.STATUS_DONE, 'done')
    )
    status = AliasesChoiceFilter(choices=STATUSES)

И API-маршрут /app/model?status=active работает правильно, устанавливая правильный статус при фильтрации.

Но! Это решение не будет работать для Django Admin или через веб-интерфейс API, поскольку оно будет предлагать реальные значения и будет пытаться передать 0 вместо active

...