#29407: django.forms field in edit dialog don't display default values
-------------------------------------+-------------------------------------
Reporter: avolkov | Owner: nobody
Type: Bug | Status: new
Component: | Version: 2.0
Uncategorized | Keywords: forms,
Severity: Normal | django.forms, fields
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 1
UI/UX: 0 |
-------------------------------------+-------------------------------------
I created a project with Django 2.0.4 running on Python 3.6.5 with
cookiecutter django template.
I created an app (survey) then created a form using a model with model
form interface view and template. Everything works except when I added a
form for editing existing model values, the form fields with default
values don't get populated. Here's a snippet from my implementation:
{{{
#!div style="font-size: 80%"
models.py
{{{#!python
from django.db import models
class Survey(models.Model):
class Meta:
"""Set composite key for file_number/location fields"""
unique_together = (('file_number', 'court_location', ))
file_number = models.CharField(max_length=127)
location = models.ForeignKey(Location, on_delete=models.PROTECT)
}}}
}}}
{{{
#!div style="font-size: 80%"
forms.py
{{{#!python
from django import forms
class SurveyForm(forms.ModelForm):
"""Survey Form along with customizations"""
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# Only show locations available to the user
locations =
Location.objects.filter(contract__user_id=self.user.id)
self.fields['location'].queryset = locations
class Meta:
model = Survey
fields = '__all__'
}}}
}}}
{{{
#!div style="font-size: 80%"
views.py
{{{#!python
class SurveyEdit(View):
"""Edit form for SurveyForm class"""
def get(self, request, survey_id):
survey_obj = Survey.objects.get(id=survey_id)
survey_form = SurveyForm(
request.GET, user=request.user, instance=survey_obj)
return render(
request,
'survey_edit_form.html',
{'survey_form': survey_form, 'survey_id': survey_id}
)
def post(self, request, survey_id):
sf = SurveyForm(
request.POST,
user=request.user,
instance=Survey.objects.get(id=survey_id))
if sf.is_valid():
sf.save()
messages.add_message(
request,
messages.SUCCESS,
"Survey {} was
updated".format(sf.cleaned_data['file_number'])
)
return HttpResponseRedirect('/survey/list')
error_message(sf, request)
return render(
request,
'survey_edit_form.html',
{'survey_form': sf, 'survey_id': survey_id}
)
}}}
}}}
{{{
#!div style="font-size: 80%"
survey_edit_form.html
{{{#!jinja
{% extends "base.html" %}
{% block title %}
{% block head_title %}
Edit Survey
{% endblock head_title %}
{% endblock title %}
{% block content %}
<div class="row">
<div class="col-md-6 offset-md-3">
<form action="{% url "survey:edit" survey_id=survey_id %}"
method=POST>
{% csrf_token %}
{% for field in survey_form %}
<div class='form-group'>
<div class='label'>{{ field.label }}</div>
{{ field }}
</div>
{% endfor %}
<input type="submit" value="Submit">
</form>
</div>
</div>
{% endblock %}
}}}
}}}
{{{
#!div style="font-size: 80%"
url.py
{{{#!python
path('edit/<int:survey_id>', login_required(SurveyEdit.as_view()),
name='edit'),
}}}
}}}
I also have the following test case, which verifiees that the data is
loaded into the form
{{{
#!div style="font-size: 80%"
tests.py
{{{#!python
def test_006_edit_data_is_loaded(self):
"""When editing a survey through SurveyForm, verify Survey data is
loaded"""
client = Client()
client.force_login(self.user)
# create survey object from generated data
edit_survey_data = copy(gen_survey_data(self))
edit_survey = Survey(**edit_survey_data)
edit_survey.save()
# go to edit page
edit_url = '/survey/edit/{}'.format(edit_survey.id)
resp = client.get(edit_url)
# verify that field values were loaded
content = str(resp.content)
self.assertIn(edit_survey_data['file_number'], content)"
}}}
}}}
The problem seems to be somewhere either in django.forms.boundfield
https://github.com/django/django/blob/c591bc3ccece1514d6b419826c7fa36ada9d9213/django/forms/boundfield.py#L126
{{{
#!div style="font-size: 80%"
{{{#!python
def value(self):
data = self.initial
if self.form.is_bound:
data = self.field.bound_data(self.data, data)
return self.field.prepare_value(data)
}}}
}}}
Where data is correctly assigned from self.initial value (which is taken
from instance param passed to SurveyForm). However, self.field.bound_data
method seems to return wrong value,
https://github.com/django/django/blob/c591bc3ccece1514d6b419826c7fa36ada9d9213/django/forms/fields.py#L161
{{{
#!div style="font-size: 80%"
In this code snippet:
{{{#!python
if self.disabled:
return initial
return data
}}}
}}}
The initial value returned only when the field is disabled, which should
not be the case, I want default data to be displayed when request.GET is
passed to render ModelForm, in my case the check should be, if there's no
updated data, return initial data i.e.
{{{
#!div style="font-size: 80%"
Code highlighting:
{{{#!python
if data:
return data
return initial
}}}
}}}
This seems to fix the issue I have and when I make the change the default
values are displayed in edit field, however I looked at history of these
two files (git blame) and didn't find anything that's been changed
recently (all the changes are from 2-3 years ago), so I'm not sure if this
is something I'm doing wrong or there was a bug introduced in django.forms
in some other way?
--
Ticket URL: <https://code.djangoproject.com/ticket/29407>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/050.de053d5b2f22d1edb88373e2b9652de1%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.