Creating a dynamic choice field
Solution 1
you can filter the waypoints by passing the user to the form init
class waypointForm(forms.Form):
def __init__(self, user, *args, **kwargs):
super(waypointForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ChoiceField(
choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
)
from your view while initiating the form pass the user
form = waypointForm(user)
in case of model form
class waypointForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(waypointForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ModelChoiceField(
queryset=Waypoint.objects.filter(user=user)
)
class Meta:
model = Waypoint
Solution 2
There's built-in solution for your problem: ModelChoiceField.
Generally, it's always worth trying to use ModelForm
when you need to create/change database objects. Works in 95% of the cases and it's much cleaner than creating your own implementation.
Solution 3
the problem is when you do
def __init__(self, user, *args, **kwargs):
super(waypointForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])
in a update request, the previous value will lost!
Solution 4
You can declare the field as a first-class attribute of your form and just set choices dynamically in __init__
:
class WaypointForm(forms.Form):
waypoints = forms.ChoiceField(choices=[])
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
self.fields['waypoints'].choices = waypoint_choices
This approach also works with a ModelChoiceField.
This approach is superior if you are using a ModelForm, and want to override choices of an autogenerated field.
Solution 5
How about passing the rider instance to the form while initializing it?
class WaypointForm(forms.Form):
def __init__(self, rider, *args, **kwargs):
super(joinTripForm, self).__init__(*args, **kwargs)
qs = rider.Waypoint_set.all()
self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])
# In view:
rider = request.user
form = WaypointForm(rider)
whatWhat
Updated on April 25, 2020Comments
-
whatWhat about 4 years
I'm having some trouble trying to understand how to create a dynamic choice field in django. I have a model set up something like:
class rider(models.Model): user = models.ForeignKey(User) waypoint = models.ManyToManyField(Waypoint) class Waypoint(models.Model): lat = models.FloatField() lng = models.FloatField()
What I'm trying to do is create a choice Field whos values are the waypoints associated with that rider (which would be the person logged in).
Currently I'm overriding init in my forms like so:
class waypointForm(forms.Form): def __init__(self, *args, **kwargs): super(joinTripForm, self).__init__(*args, **kwargs) self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])
But all that does is list all the waypoints, they're not associated with any particular rider. Any ideas? Thanks.
-
Daniel Roseman almost 14 yearsUse ModelChoiceField whether or not it's a ModelForm - it works on normal forms too.
-
Breedly over 10 yearsWhat do you do when you want to get the request data out though? waypointForm(request.POST) won't validate in the first one, because the data to validate against isn't there anymore.
-
wasabigeek over 8 years@Ashok How could the CheckboxSelectMultiple widget be used in this instance? For the modelform especially.
-
coredumperror almost 8 yearsIf you want to use the
CheckboxSelectMultiple
widget with this, you'll want to useMultipleChoiceField
orModelMultipleChoiceField
. At first, it seems to work withChoiceField
, but the internals will break when you try to save the form. -
sofly almost 8 yearsThank you @CoreDumpError - just fought this for nearly 2 hours before reading your comment (doh!) and this finally made everything work. Others, beware of breaking your form submission (unicode issues) if you plan on using the
CheckboxSelectMultiple
widget with this code. Be sure to changeChoiceForm
toMultipleChoiceForm
-
MohitC over 7 years
user
should be passed as kwargs so thatrequest
is preserved as first positional arg. -
Raptor about 6 yearsExactly what I was looking for! Thanks!
-
Aravind R Pillai over 5 yearsthis made my life easier.. Thanks a lot.. :)
-
ineedme about 5 yearstry using values_list("id","str") instead of array compression
-
jpmorris about 4 yearsthis is NOT the answer. This is the BROKEN answer all over the internet. 'user' should not be in the init signature. As mentioned above when you do this if you do any binding or validation to actually use the form (as recommended in the docs) then you cant bind any data to the form because you just changed the request.POST position to 'user' now. This answer needs to stop being upvoted.
-
Alan Evangelista about 3 years@jpmorris If this answer is broken, could you write a better one?
-
jpmorris about 3 years@AlanEvangelista sorry I barely worked with django at the time and I don't know the answer. Actually I'm not sure I even knew the answer at the time. I only knew that this wasnt the one.