Django(trunk) and class based generic views: one form's initial data appearing in another one's
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).
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
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)
精彩评论