DRF: Установить значение по умолчанию поля выбора программно из запроса БД
Я задавал похожий вопрос здесь об установке значения по умолчанию для поля TextChoices в модели. Теперь я перехожу на следующий уровень.
Я перенес настройки выбора из модели в сериализатор ChoiceField
. Сайт представляет собой Django/DRF/django_tenants backend с Vue frontend. Я хочу, чтобы фронтенд и бэкенд использовали один и тот же набор вариантов выбора и, что не менее важно, одни и те же значения по умолчанию. Поэтому я создал таблицу OptionGroup. Вот два примера строк из этой таблицы (некоторые опции опущены):
{
"results": {
"id": 1,
"name": "payment_method",
"defined_in": "option_table",
"default_option": "5",
"options": [
{
"id": 2,
"name": "Bank Transfer",
"value": "2"
},
{
"id": 5,
"name": "Credit Card",
"value": "5"
},
{
"id": 8,
"name": "PayPal",
"value": "8"
}
]
}
}
{
"results": {
"id": 3,
"name": "invoice_type",
"defined_in": "class",
"app_label": "invoices",
"choices_class": "InvoiceType",
"default_option": "standard",
"options": [
{
"name": "Standard",
"value": "standard"
},
{
"name": "Retainer",
"value": "retainer"
},
{
"order": 1,
"name": "Estimate",
"value": "estimate"
}
]
}
}
Первый (defined_in = "option_table") имеет свои опции, определенные в связанной модели Option. У второго опции определены в подклассе TextChoices в коде бэкенда. Помимо синхронизации фронтэнда и бэкэнда для опций и значений по умолчанию, это также позволит пользователям установить, какую опцию для каждого поля списка выбора они хотят использовать в качестве значения по умолчанию. Обратите внимание на поле default_option
выше.
Я создал класс, расширенный из класса ChoiceField
(из DRF), и добавил логику в метод __init__()
, чтобы получить значение по умолчанию из модели OptionGroup и установить его для определяемого поля сериализатора.
class CustomChoiceField(serializers.ChoiceField):
def __init__(self, choices, **kwargs):
option_group = kwargs.pop('option_group', None)
if option_group and 'default' not in kwargs:
group = OptionGroup.objects.filter(name__iexact=option_group)
if group and group.default_option:
kwargs['default'] = group.default_option
super().__init__(choices, **kwargs)
А вот как его используют:
type = CustomChoiceField(
choices=choices.InvoiceType.choices,
option_group='invoice_type',
)
Проблема в том, что активной схемой в этот момент является "public", а не реальная схема арендатора. Похоже, что __init__()
для моего пользовательского класса выполняется слишком рано в процессе запроса - до того, как django_tenants подключится к нужной схеме.
У кого-нибудь есть предложение, как это можно сделать, или то, что я пытаюсь сделать, просто невозможно?