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.

Reply via email to