Django(trunk) and class based generic views: one f

2020-05-06 13:00发布

问题:

I've run into a strange problem where data seems to persist accross different views and requests until the server gets restarted.

I've managed to reduce the issue to the following code:

# foobar/models.py
from django.db import models

class Foo(models.Model):
    bug = models.CharField(max_length=10)


# foobar/forms.py
from django import forms
from foobar.models import Foo

class CreateForm(forms.ModelForm):
    class Meta:
        model = Foo

class UpdateForm(forms.ModelForm):
    class Meta:
        model = Foo

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('initial', {})
        kwargs['initial'].update({'bug': 'WHY??'})
        super(UpdateForm, self).__init__(*args, **kwargs)


# foobar/views.py
from django.views.generic.edit import CreateView, UpdateView
from foobar.forms import CreateForm, UpdateForm
from foobar.models import Foo

class FooCreateView(CreateView):
    form_class = CreateForm
    template_name = 'foobar/foo_form.html'

create = FooCreateView.as_view()

class FooUpdateView(UpdateView):
    form_class = UpdateForm
    template_name = 'foobar/foo_form.html'
    queryset = Foo.objects.all()

update = FooUpdateView.as_view()


# foobar/urls.py
from django.conf.urls.defaults import *

urlpatterns = patterns('foobar.views',
    ('^$', 'create'),
    (r'^(?P<pk>\d+)/$', 'update'),
)

You should also probably add a template (in foobar/templates/foo_form.html for example):

<form action="" method="post">
{{ form.as_p }}
<input type="submit" />
{% csrf_token %}
</form>

To reproduce, do the following:

  • Add the foobar app to settings.INSTALLED_APPS
  • Run syncdb
  • Add foobar.urls to your root urlconf
  • Navigate to /foobar/ (the actual URL will depend on your root urlconf)
  • Submit the form (thus creating a new Foo object)
  • Navigate to /foobar/1/. Notice that the form field is prepopulated (this is expected)
  • Navigate to /foobar/. Notice the form field is still populated (this is not expected).

Is this a bug or am I doing something I shouldn't be (or maybe both...)?

-- EDIT --

In forms.py, if I replace the update call by this:

kwargs['initial']['bug'] = 'WHY???'

Then the problem is still there.

Commenting out the line removes the problem (but then the form has no initial data, obviously).

回答1:

Because you're mutating the kwargs that are passed in, which come from class-level properties in the view class.

Instead, copy them and update the copy:

initial_defaults = {'bug': 'no'}
initial_defaults.update(kwargs.get('initial', {}))
defaults = kwargs.copy()
defaults['initial'] = initial_defaults 


回答2:

You might want to specify Django-1.3 development, generic class view doesn't exist in Django 1.2.5. In your forms.py file, can you comment the following lines and try again:

class UpdateForm(forms.ModelForm):
    class Meta:
        model = Foo

    def __init__(self, *args, **kwargs):
        #kwargs.setdefault('initial', {})
        #kwargs['initial'].update({'bug': 'WHY??'})
        super(UpdateForm, self).__init__(*args, **kwargs)