Form field for a foreign key in ModelForm with too many choices for ModelChoiceField?
Solution 1:
The ModelChoiceField documentation says to use something else if the number of choices is large.
The documentation suggests using a different widget (otherwise a user will have to select from a dropdown with too many items), but you don't necessarily need an entirely different field.
If you want the field of the bound form to be n instance of Sample
, then ModelChoiceField
is still appropriate.
To avoid the problem anticipated in the documentation, you could just change the widget for the field. You might need to decide exactly what that is. One simple choice would be to use a NumberInput
widget where the user just enters an integer for the foreign key.
from django.forms.widgets import NumberInput
class AssignmentForm(ModelForm):
sample = ModelChoiceField(queryset=Sample.objects.all(), widget=NumberInput)
class Meta:
model = Assignment
fields = ['sample']
select the sample based on the contents of the sample's alt field
What you want here is a separate issue from what you quoted from the documentation. You can choose to implement this with or without changing the widget.
If you want the user to provide the alt
value rather than the primary key of the Sample, you can use the to_field_name
argument for ModelChoiceField
(note this is only appropriate here because your alt
field is unique)
class AssignmentForm(ModelForm):
sample = ModelChoiceField(
queryset=Sample.objects.all(),
widget=NumberInput,
help_text="Enter the alt of the sample",
to_field_name='alt'
)
class Meta:
model = Assignment
fields = ["sample"]
In order for the initial value to render correctly when rendering a bound form, you can provide the initial
keyword argument when instantiating the bound form:
form = AssignmentForm(instance=inst,
initial={'sample': inst.sample.alt})
Alternatively, you can override the __init__
method of the form to do this automatically when the form is instantiated:
class AssignmentForm(ModelForm):
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.pk:
self.initial.update({'sample': self.instance.sample.alt})