Fixed #12337 - Honor ModelForm.Meta.exclude when saving ManyToManyFields.
Thanks margieroginski for the report.
This commit is contained in:
parent
b67f2ac8e6
commit
e2518fdf46
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
Loading…
Reference in New Issue