I'm trying to update a model object where one of the values is derived from a queryset. The object creation works perfectly - it uses a queryset that is passed to the template and then on the POST it is saved into the object.
My Question: The field named parent_jury is showing up in the template as an empty choicefield. It doesn't contain the original field value. How do I get it to set the initial field value to what is in the object and allow the user to select from other values in the queryset?
But now I'm trying to update the object. Here's the code:
#forms.py
def __init__(self, *args, **kwargs):
pk = kwargs.pop('pk')
yr = kwargs.pop('yr')
jr = kwargs.pop('jr')
self.customer_id = pk
self.court_year_id = yr
super().__init__(*args, **kwargs)
# This prints the correct value for the the object I'm trying to update
print("pr: ", Jury.objects.get(
jury_id=jr).parent_jury)
# This is my latest attempt to get the initial value (or any value) to
# be presented in the modelform/template.
self.fields['parent_jury'].initial = Jury.objects.get(
jury_id=jr).parent_jury
Besides the code above, I've also tried to pull the right __init__() values using this:
#forms.py (other attempts)
self.fields['parent_jury'] = forms.ChoiceField(
required = False,
choices = Jury.objects.filter(
customer_id=pk).filter(
court_year_id = yr),
initial = Juriy.objects.get(
jury_id=jr).parent_jury)
My template mirrors my createview template (likely causing part of the issue).
#template.html
<tr><td>Parent Jury:</td><td><select name="parent_jury">
{% for item in form.parent_jury.field.queryset %}
<option value="{{ item }}">{{ item }}</option>
{% endfor %}
</select></td></tr>
I did run across this, but it is using a separate filter class - I was hoping to handle in the __init__.
There is a strong possibility that my issue is actually in the template - I came across this, but would still rather manage what gets delivered (and how) within the ModelForm.
Follow-on Question:
OR... is it possible to pass the initial value into the template withe everything else and then code it into the template?
Update I
I've almost figured it out - Here is the forms.py __ini__() that will pass the right choices to the template:
def __init__(self, *args, **kwargs):
pk = kwargs.pop('pk')
yr = kwargs.pop('yr')
jr = kwargs.pop('jr')
self.customer_id = pk
self.court_year_id = yr
super().__init__(*args, **kwargs)
print("pr: ", Juriy.objects.get(
jury_id=jr).parent_jury)
choices = list(Jury.objects.filter(
client_id = pk).filter(
court_year_id = yr).values_list('jury_name', 'jury_name'))
print("choices: ", choices)
self.fields['parent_jury'] = forms.ChoiceField(
choices = choices,
)
In the .values_list() I've included 'jury_name' twice to get the list item to work. With only one value the template below throws the err: not enough values to unpack (expected 2, got 1). Passing two solves this problem.
In the templates I have:
<tr><td>Parent Jury:</td><td><select name="parent_jury">
{% for item in form.parent_jury %}
<option value="{{ item }}">{{ item }}</option>
{% endfor %}
</select></td></tr>
#output
Thingy1
Thingy1
Thingy2
Thingy2
Thingy3
Thingy3
As you can see, now the problem is that the select/option field on the form actually duplicates the key entries. Each key is shown twice in the drop down menu.
I've also run the following code on the bottom of the template with the correct result:
{% for item in form.parent_jurisdiction %}
{{item}}
{% endfor %}
#output
Thingy1
Thingy2
Thingy3
How do I fix that?
Update II
My answer below is wrong... Although the removal of the {{ item }} label does in fact change the options to include only a single set of choices - it doesn't pass in the POST - instead I get this in the POST report:
parent_jury '<option value='
So, getting closer - The view is correct, but the selected choice isn't being passed back.
Update III
Found the right construct for the template... answer updated:
Original SO answer for the template can be found here.