Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #12337 - Honor ModelForm.Meta.exclude when saving ManyToManyFie…

…lds.

Thanks margieroginski for the report.
  • Loading branch information...
commit e2518fdf46a687454066b8a75263c9019b1e965d 1 parent b67f2ac
Stephen Burrows melinath authored timgraham committed
Showing with 41 additions and 2 deletions.
  1. +4 −1 django/forms/models.py
  2. +37 −1 tests/forms_tests/tests/tests.py
5 django/forms/models.py
View
@@ -85,6 +85,8 @@ def save_m2m():
for f in opts.many_to_many:
if fields and f.name not in fields:
continue
+ if exclude and f.name in exclude:
+ continue
if f.name in cleaned_data:
f.save_form_data(instance, cleaned_data[f.name])
if commit:
@@ -405,7 +407,8 @@ def save(self, commit=True):
else:
fail_message = 'changed'
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
38 tests/forms_tests/tests/tests.py
View
@@ -5,7 +5,7 @@
from django.core.files.uploadedfile import SimpleUploadedFile
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.test import TestCase
from django.utils import six
@@ -26,6 +26,14 @@ class Meta:
fields = '__all__'
+class ChoiceFieldExclusionForm(ModelForm):
+ multi_choice = CharField(max_length=50)
+
+ class Meta:
+ exclude = ['multi_choice']
+ model = ChoiceFieldModel
+
+
class FileForm(Form):
file1 = FileField()
@@ -221,3 +229,31 @@ class Meta:
model=A
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'])
Please sign in to comment.
Something went wrong with that request. Please try again.