1👍
First point: model forms are for creating / editing models, so you should use plain forms here. Your error comes from having the make
field in your ModelSelectForm
but not setting its value anywhere. Also, ModelChoiceField
is meant to retrieve a model instance, not field’s value, so you really want a ChoiceField
here.
Second point, since your goal is to display filtered informations – not to create or edit anything -, you should use GET
queries (like for any “search” feature actually).
For your second form to work as expected (once ported to a plain Form
with a single model
field), you’ll need to pass the make
value to the form and, in the form’s __init__()
, update the model
fields choices to the filtered queryset.
Also since you’ll be using GET
as form’s method, you’ll have to check wether the form has been submitted at all before deciding to instanciate it with or without the request.GET
data, 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:
class ModelSelectForm(forms.Form):
model = forms.ChoiceField()
def __init__(self, *args, **kwargs):
make = kwargs.pop("make", None)
if not make:
raise ValueError("expected a 'make' keyword arg")
super(ModelSelectForm, self).__init__(*args, **kwargs)
qs = Car.objects.filter(make=make).values_list('model',flat=True).distinct()
choices = [(value, value) for value in qs]
self.fields["model"].choices = choices
Views:
def model_select_view(request, make):
model = None
if request.GET.get("submitted", None):
form = ModelSelectForm(request.GET, make=make)
if form.is_valid():
model = form.cleaned_data['model']
else:
form = ModelSelectForm(make=make)
context = {"form": form, "model": model, "make: make}
return render(request, "reviews/modelselect.html", context)
Templates:
<form action="{% url 'reviews:model-select' make %}" method="GET">
{% csrf_token %}
<input type="hidden" name="submitted" value="1" />
{{ form.as_p }}
<input type="submit" value="Select" />
</form>
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-select
view, 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:
def make_select_view(request):
if request.GET.get("submitted", None):
form = MakeSelectForm(request.GET)
if form.is_valid():
make = form.cleaned_data['make']
# send the user to the model selection view
return redirect("reviews:model-select", make=make)
else:
form = MakeSelectForm()
context = {"form": form}
return render(request, "reviews/makeselect.html", context)
1👍
Since the formatting of the snippet that I posted in comment got messed up so, I am writing that as an answer here.
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(GameForm, self).__init__(*args, **kwargs)
if not self.request.user.is_staff:
self.fields['publisher'].queryset = Publisher.objects.filter(id=self.request.user.id)
- [Answered ]-Generate PDF of Protected Django Webpage with Attachments
- [Answered ]-Django admin page adding save as pdf button
- [Answered ]-Pointing Django to Different Template Directory
- [Answered ]-Django ajax follow and unfollow
- [Answered ]-Django Rest Framework: How to get value of the ForeignKey