Разрешить выбор пустого внешнего ключа в формах администратора

Я создал модель (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. Похоже, что стандартное пустое значение для внешнего ключа "------" не является допустимым выбором.

enter image description here

@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

Вернуться на верх