Fixed #12337 - Honor ModelForm.Meta.exclude when saving ManyToManyFields.

Thanks margieroginski for the report.
This commit is contained in:
Stephen Burrows 2012-09-27 19:04:40 -07:00 committed by Tim Graham
parent b67f2ac8e6
commit e2518fdf46
2 changed files with 41 additions and 2 deletions

View File

@ -85,6 +85,8 @@ def save_instance(form, instance, fields=None, fail_message='saved',
for f in opts.many_to_many: for f in opts.many_to_many:
if fields and f.name not in fields: if fields and f.name not in fields:
continue continue
if exclude and f.name in exclude:
continue
if f.name in cleaned_data: if f.name in cleaned_data:
f.save_form_data(instance, cleaned_data[f.name]) f.save_form_data(instance, cleaned_data[f.name])
if commit: if commit:
@ -405,7 +407,8 @@ class BaseModelForm(BaseForm):
else: else:
fail_message = 'changed' fail_message = 'changed'
return save_instance(self, self.instance, self._meta.fields, return save_instance(self, self.instance, self._meta.fields,
fail_message, commit, construct=False) fail_message, commit, self._meta.exclude,
construct=False)
save.alters_data = True save.alters_data = True

View File

@ -5,7 +5,7 @@ import datetime
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.db import models from django.db import models
from django.forms import Form, ModelForm, FileField, ModelChoiceField from django.forms import Form, ModelForm, FileField, ModelChoiceField, CharField
from django.forms.models import ModelFormMetaclass from django.forms.models import ModelFormMetaclass
from django.test import TestCase from django.test import TestCase
from django.utils import six from django.utils import six
@ -26,6 +26,14 @@ class OptionalMultiChoiceModelForm(ModelForm):
fields = '__all__' fields = '__all__'
class ChoiceFieldExclusionForm(ModelForm):
multi_choice = CharField(max_length=50)
class Meta:
exclude = ['multi_choice']
model = ChoiceFieldModel
class FileForm(Form): class FileForm(Form):
file1 = FileField() file1 = FileField()
@ -221,3 +229,31 @@ class RelatedModelFormTests(TestCase):
model=A model=A
self.assertTrue(issubclass(ModelFormMetaclass(str('Form'), (ModelForm,), {'Meta': Meta}), ModelForm)) self.assertTrue(issubclass(ModelFormMetaclass(str('Form'), (ModelForm,), {'Meta': Meta}), ModelForm))
class ManyToManyExclusionTestCase(TestCase):
def test_m2m_field_exclusion(self):
# Issue 12337. save_instance should honor the passed-in exclude keyword.
opt1 = ChoiceOptionModel.objects.create(id=1, name='default')
opt2 = ChoiceOptionModel.objects.create(id=2, name='option 2')
opt3 = ChoiceOptionModel.objects.create(id=3, name='option 3')
initial = {
'choice': opt1,
'choice_int': opt1,
}
data = {
'choice': opt2.pk,
'choice_int': opt2.pk,
'multi_choice': 'string data!',
'multi_choice_int': [opt1.pk],
}
instance = ChoiceFieldModel.objects.create(**initial)
instance.multi_choice = instance.multi_choice_int = [opt2, opt3]
form = ChoiceFieldExclusionForm(data=data, instance=instance)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['multi_choice'], data['multi_choice'])
form.save()
self.assertEqual(form.instance.choice.pk, data['choice'])
self.assertEqual(form.instance.choice_int.pk, data['choice_int'])
self.assertEqual(list(form.instance.multi_choice.all()), [opt2, opt3])
self.assertEqual([obj.pk for obj in form.instance.multi_choice_int.all()], data['multi_choice_int'])