﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
29407	django.forms field in edit dialog don't display default values	Alex Volkov		"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?"	Bug	closed	Uncategorized	2.0	Normal	invalid	forms, django.forms, fields		Unreviewed	0	0	0	0	1	0
