'Allow empty foreign key selection in admin forms
I created a model(AnalysisFieldTemplate) with a foreign key to AnalysisFieldRule. What i want is to have the possibility to leave the field display_analysis_field_rule blank and save my admin form.
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"),
)
Now here is the problem. If i try to save my admin form without choosing one a value for display_analysis_field_rule it will result in an Validationerror. It seems that the standard empty value for a foreign key "------" is not a valid choice.
@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")}),
)
I debugged a little deeper and found that the "to_python" compares the choosen value with pythons standard "empty_values" but of course it contains not the "------" and it will handle it as a normal id which results in an Validation error.
My question is how can i make it possible to save my form without choosing a value for my foreign key? Do i have to override the "to_python" function? What would be a best practice here?
I appreciate all the help :)
Solution 1:[1]
The solution which worked for me was to create a custom form and override the empy_values for each of my foreing keys with its 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
Solution 2:[2]
You need to create custom modelform for your use case and make the particular field with 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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | David Marogy |
Solution 2 |