Hello everyone, I'm having some problem with django.forms edit dialog and I believe it might be a bug in django that's causing this.
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 template {% 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 %} # urls.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 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 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 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. 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. Please help. -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com. To post to this group, send email to django-users@googlegroups.com. Visit this group at https://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/ef9f9d61-cd62-4c20-b9e6-cc7279cb33fc%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.