Разрешить выбор пустого внешнего ключа в формах администратора
Я создал модель (AnalysisFieldTemplate) с внешним ключом к AnalysisFieldRule. Я хочу иметь возможность оставить поле display_analysis_field_rule пустым и сохранить мою административную форму.
class AnalysisFieldRule(models.Model):
action_kind: str = models.CharField(
choices=ActionKind.choices,
default=ActionKind.DISPLAY,
max_length=text_choices_max_length(ActionKind),
verbose_name=_("action kind"),
)
formula: str = formula_field()
name: str = models.CharField(max_length=MAX_NAME_LENGTH, verbose_name=_("name"))
def __str__(self):
return f"{self.name}: {ActionKind(self.action_kind).label}"
class Meta:
constraints = [
UniqueConstraint(fields=("action_kind", "name"), name="%(app_label)s_%(class)s_is_unique"),
]
ordering = ["name", "action_kind"]
verbose_name = _("analysis field rule")
verbose_name_plural = _("analysis field rules")
class AnalysisFieldTemplate(models.Model):
display_analysis_field_rule: AnalysisFieldRule = models.ForeignKey(
AnalysisFieldRule,
blank=True,
limit_choices_to={"action_kind": ActionKind.DISPLAY},
null=True,
on_delete=models.PROTECT,
related_name="display_analysis_field_templates",
verbose_name=_("display rule"),
)
Теперь вот в чем проблема. Если я попытаюсь сохранить мою административную форму без выбора значения для display_analysis_field_rule, это приведет к ошибке Validationerror. Похоже, что стандартное пустое значение для внешнего ключа "------" не является допустимым выбором.
@admin.register(AnalysisFormTemplate)
class AnalysisFieldTemplateAdmin(admin.ModelAdmin):
fieldsets = (
(
None,
{
"fields": (
"name",
"name_for_formula",
"ordering",
"required",
"kind",
"display_analysis_field_rule",
"highlight_analysis_field_rule",
)
},
),
(
_("Text options"),
{"fields": ("max_length",)},
),
(
_("Integer options"),
{"fields": ("min_integer_value", "max_integer_value")},
),
(_("Amount of money options"), {"fields": ("min_amount_of_money", "max_amount_of_money")}),
)
Я отладил немного глубже и обнаружил, что "to_python" сравнивает выбранное значение со стандартным "empty_values" питона, но, конечно, оно не содержит "------" и будет обрабатывать его как обычный id, что приводит к ошибке Validation.
Мой вопрос в том, как я могу сделать возможным сохранение моей формы без выбора значения для внешнего ключа? Должен ли я переопределить функцию "to_python"? Что здесь может быть лучшей практикой?
Я ценю любую помощь :)
Вам необходимо создать пользовательскую форму модели для вашего случая использования и сделать конкретное поле с required=False
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['display_analysis_field_rule'].required = False
self.fields['display_analysis_field_rule'].empty_label = None
class Meta:
model = MyModel # Put your model name here
@admin.register(AnalysisFormTemplate)
class AnalysisFieldTemplateAdmin(admin.ModelAdmin):
form = MyForm
# .... your stuff
Решением, которое сработало для меня, было создание пользовательской формы и переопределение empy_values для каждого из моих правящих ключей с его empty_label.
from django.core.validators import EMPTY_VALUES # NOQA
def empty_values_list_for_foreign_key(empty_label:str):
empty_values_list = list(EMPTY_VALUES)
empty_values_list.append(empty_label)
return empty_values_list
class AnalysisFieldTemplateAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["display_analysis_field_rule"].empty_values = empty_values_list_for_foreign_key(self.fields["display_analysis_field_rule"].empty_label)
self.fields["highlight_analysis_field_rule"].empty_values = empty_values_list_for_foreign_key(self.fields["highlight_analysis_field_rule"].empty_label)
@admin.register(AnalysisFieldTemplate)
class AnalysisFieldTemplateAdmin(admin.ModelAdmin):
form = AnalysisFieldTemplateAdminForm
