I have a single Car model which I'd like to filter through interdependent ModelChoiceField's:
class Car(models.Model):
make = models.CharField(max_length=50)
model = models.CharField(max_length=50)
platform = models.CharField(max_length=50)
Forms.py:
class MakeSelectForm(forms.ModelForm):
make = forms.ModelChoiceField(queryset=Car.objects.values_list('make',flat=True).distinct())
class Meta:
model = Car
fields = ["make"]
class ModelSelectForm(forms.ModelForm):
model = forms.ModelChoiceField(queryset=Car.objects.values_list('model',flat=True).distinct())
class Meta:
model = Car
fields = ["make", "model"]
Views.py:
def make_select_view(request):
form = MakeSelectForm()
make = None
if request.method == "POST":
form = MakeSelectForm(request.POST)
if form.is_valid():
make = form.cleaned_data['make']
return render(request, "reviews/makeselect.html", {"form": form, "make": make})
def model_select_view(request, make):
form = ModelSelectForm()
model = None
if request.method == "POST":
form = MakeSelectForm(request.POST)
if form.is_valid():
model = form.cleaned_data['model']
return render(request, "reviews/modelselect.html", {"form": form, "model": model})
URL's:
urlpatterns = [
url(r'^$', views.make_select_view, name="make-select"),
url(r'^(?P<make>\w+)/$', views.model_select_view, name="model-select"),
]
Makeselect.html:
<form action="{% url 'reviews:model-select' make %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Select" />
</form>
Now, I have to pass "make" argument of the first form when posted, to the second view, and then use it to filter through Car instances with that make. But here all I pass is "None", and get Select a valid choice. That choice is not one of the available choices. error in the second form.
Any suggestion or feedback will be welcomed and greatly appreciated.
Thank you.
First point: model forms are for creating / editing models, so you should use plain forms here. Your error comes from having the
makefield in yourModelSelectFormbut not setting its value anywhere. Also,ModelChoiceFieldis meant to retrieve a model instance, not field's value, so you really want aChoiceFieldhere.Second point, since your goal is to display filtered informations - not to create or edit anything -, you should use
GETqueries (like for any "search" feature actually).For your second form to work as expected (once ported to a plain
Formwith a singlemodelfield), you'll need to pass themakevalue to the form and, in the form's__init__(), update themodelfields choices to the filtered queryset.Also since you'll be using
GETas form's method, you'll have to check wether the form has been submitted at all before deciding to instanciate it with or without therequest.GETdata, else the users would get error messages on first display before they even had a chance to submit anything. This is usually solved using either a name and value for the form's submit button or a hidden field in the form itself:Forms:
Views:
Templates:
wrt/ your question about "passing 'make' to the second view": there's nowhere in your code snippet where you direct the user to the
model-selectview, but I assume that what you want is the user being redirected to it once he successfully selected the "make" in the first view. If yes, your first view's code should handle the case on successful form submission, ie: