Opened 6 years ago
Closed 6 years ago
#29407 closed Bug (invalid)
django.forms field in edit dialog don't display default values
Reported by: | Alex Volkov | Owned by: | |
---|---|---|---|
Component: | Uncategorized | Version: | 2.0 |
Severity: | Normal | Keywords: | forms, django.forms, fields |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | yes | UI/UX: | no |
Description
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:
models.py
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)
forms.py
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__'
views.py
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} )
survey_edit_form.html
{% 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 %}
url.py
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
tests.py
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
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,
In this code snippet:
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.
Code highlighting:
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?
Thanks for the report, but I would suggest you first search help in Django support channels and ensure that Django is at fault before opening a ticket.
I'm sure reading https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/ could already help you.