diff options
Diffstat (limited to 'tests/model_forms/tests.py')
| -rw-r--r-- | tests/model_forms/tests.py | 1898 |
1 files changed, 1145 insertions, 753 deletions
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index db36216d14..dd397785a1 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -5,13 +5,19 @@ from unittest import mock, skipUnless from django import forms from django.core.exceptions import ( - NON_FIELD_ERRORS, FieldError, ImproperlyConfigured, ValidationError, + NON_FIELD_ERRORS, + FieldError, + ImproperlyConfigured, + ValidationError, ) from django.core.files.uploadedfile import SimpleUploadedFile from django.db import connection, models from django.db.models.query import EmptyQuerySet from django.forms.models import ( - ModelFormMetaclass, construct_instance, fields_for_model, model_to_dict, + ModelFormMetaclass, + construct_instance, + fields_for_model, + model_to_dict, modelform_factory, ) from django.template import Context, Template @@ -19,15 +25,51 @@ from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test.utils import isolate_apps from .models import ( - Article, ArticleStatus, Author, Author1, Award, BetterWriter, BigInt, Book, - Category, Character, Colour, ColourfulItem, CustomErrorMessage, CustomFF, - CustomFieldForExclusionModel, DateTimePost, DerivedBook, DerivedPost, Dice, - Document, ExplicitPK, FilePathModel, FlexibleDatePost, Homepage, - ImprovedArticle, ImprovedArticleWithParentLink, Inventory, - NullableUniqueCharFieldModel, Number, Person, Photo, Post, Price, Product, - Publication, PublicationDefaults, StrictAssignmentAll, - StrictAssignmentFieldSpecific, Student, StumpJoke, TextFile, Triple, - Writer, WriterProfile, test_images, + Article, + ArticleStatus, + Author, + Author1, + Award, + BetterWriter, + BigInt, + Book, + Category, + Character, + Colour, + ColourfulItem, + CustomErrorMessage, + CustomFF, + CustomFieldForExclusionModel, + DateTimePost, + DerivedBook, + DerivedPost, + Dice, + Document, + ExplicitPK, + FilePathModel, + FlexibleDatePost, + Homepage, + ImprovedArticle, + ImprovedArticleWithParentLink, + Inventory, + NullableUniqueCharFieldModel, + Number, + Person, + Photo, + Post, + Price, + Product, + Publication, + PublicationDefaults, + StrictAssignmentAll, + StrictAssignmentFieldSpecific, + Student, + StumpJoke, + TextFile, + Triple, + Writer, + WriterProfile, + test_images, ) if test_images: @@ -36,59 +78,62 @@ if test_images: class ImageFileForm(forms.ModelForm): class Meta: model = ImageFile - fields = '__all__' + fields = "__all__" class OptionalImageFileForm(forms.ModelForm): class Meta: model = OptionalImageFile - fields = '__all__' + fields = "__all__" class NoExtensionImageFileForm(forms.ModelForm): class Meta: model = NoExtensionImageFile - fields = '__all__' + fields = "__all__" class ProductForm(forms.ModelForm): class Meta: model = Product - fields = '__all__' + fields = "__all__" class PriceForm(forms.ModelForm): class Meta: model = Price - fields = '__all__' + fields = "__all__" class BookForm(forms.ModelForm): class Meta: model = Book - fields = '__all__' + fields = "__all__" class DerivedBookForm(forms.ModelForm): class Meta: model = DerivedBook - fields = '__all__' + fields = "__all__" class ExplicitPKForm(forms.ModelForm): class Meta: model = ExplicitPK - fields = ('key', 'desc',) + fields = ( + "key", + "desc", + ) class PostForm(forms.ModelForm): class Meta: model = Post - fields = '__all__' + fields = "__all__" class DerivedPostForm(forms.ModelForm): class Meta: model = DerivedPost - fields = '__all__' + fields = "__all__" class CustomWriterForm(forms.ModelForm): @@ -96,89 +141,92 @@ class CustomWriterForm(forms.ModelForm): class Meta: model = Writer - fields = '__all__' + fields = "__all__" class BaseCategoryForm(forms.ModelForm): class Meta: model = Category - fields = '__all__' + fields = "__all__" class ArticleForm(forms.ModelForm): class Meta: model = Article - fields = '__all__' + fields = "__all__" class RoykoForm(forms.ModelForm): class Meta: model = Writer - fields = '__all__' + fields = "__all__" class ArticleStatusForm(forms.ModelForm): class Meta: model = ArticleStatus - fields = '__all__' + fields = "__all__" class InventoryForm(forms.ModelForm): class Meta: model = Inventory - fields = '__all__' + fields = "__all__" class SelectInventoryForm(forms.Form): - items = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode') + items = forms.ModelMultipleChoiceField( + Inventory.objects.all(), to_field_name="barcode" + ) class CustomFieldForExclusionForm(forms.ModelForm): class Meta: model = CustomFieldForExclusionModel - fields = ['name', 'markup'] + fields = ["name", "markup"] class TextFileForm(forms.ModelForm): class Meta: model = TextFile - fields = '__all__' + fields = "__all__" class BigIntForm(forms.ModelForm): class Meta: model = BigInt - fields = '__all__' + fields = "__all__" class ModelFormWithMedia(forms.ModelForm): class Media: - js = ('/some/form/javascript',) - css = { - 'all': ('/some/form/css',) - } + js = ("/some/form/javascript",) + css = {"all": ("/some/form/css",)} class Meta: model = TextFile - fields = '__all__' + fields = "__all__" class CustomErrorMessageForm(forms.ModelForm): - name1 = forms.CharField(error_messages={'invalid': 'Form custom error message.'}) + name1 = forms.CharField(error_messages={"invalid": "Form custom error message."}) class Meta: - fields = '__all__' + fields = "__all__" model = CustomErrorMessage class ModelFormBaseTest(TestCase): def test_base_form(self): - self.assertEqual(list(BaseCategoryForm.base_fields), ['name', 'slug', 'url']) + self.assertEqual(list(BaseCategoryForm.base_fields), ["name", "slug", "url"]) def test_no_model_class(self): class NoModelModelForm(forms.ModelForm): pass - with self.assertRaisesMessage(ValueError, 'ModelForm has no model class specified.'): + + with self.assertRaisesMessage( + ValueError, "ModelForm has no model class specified." + ): NoModelModelForm() def test_empty_fields_to_fields_for_model(self): @@ -192,6 +240,7 @@ class ModelFormBaseTest(TestCase): """ No fields on a ModelForm should actually result in no fields. """ + class EmptyPersonForm(forms.ModelForm): class Meta: model = Person @@ -204,28 +253,31 @@ class ModelFormBaseTest(TestCase): """ No fields should be set on a model instance if construct_instance receives fields=(). """ - form = modelform_factory(Person, fields="__all__")({'name': 'John Doe'}) + form = modelform_factory(Person, fields="__all__")({"name": "John Doe"}) self.assertTrue(form.is_valid()) instance = construct_instance(form, Person(), fields=()) - self.assertEqual(instance.name, '') + self.assertEqual(instance.name, "") def test_blank_with_null_foreign_key_field(self): """ #13776 -- ModelForm's with models having a FK set to null=False and required=False should be valid. """ + class FormForTestingIsValid(forms.ModelForm): class Meta: model = Student - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['character'].required = False + self.fields["character"].required = False - char = Character.objects.create(username='user', last_action=datetime.datetime.today()) - data = {'study': 'Engineering'} - data2 = {'study': 'Engineering', 'character': char.pk} + char = Character.objects.create( + username="user", last_action=datetime.datetime.today() + ) + data = {"study": "Engineering"} + data2 = {"study": "Engineering", "character": char.pk} # form is valid because required=False for field 'character' f1 = FormForTestingIsValid(data) @@ -242,18 +294,21 @@ class ModelFormBaseTest(TestCase): and the form field set to required=False should allow the field to be unset. """ + class AwardForm(forms.ModelForm): class Meta: model = Award - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['character'].required = False + self.fields["character"].required = False - character = Character.objects.create(username='user', last_action=datetime.datetime.today()) - award = Award.objects.create(name='Best sprinter', character=character) - data = {'name': 'Best tester', 'character': ''} # remove character + character = Character.objects.create( + username="user", last_action=datetime.datetime.today() + ) + award = Award.objects.create(name="Best sprinter", character=character) + data = {"name": "Best tester", "character": ""} # remove character form = AwardForm(data=data, instance=award) self.assertTrue(form.is_valid()) award = form.save() @@ -263,31 +318,34 @@ class ModelFormBaseTest(TestCase): class BookForm(forms.ModelForm): class Meta: model = Book - fields = ['author'] - widgets = {'author': forms.RadioSelect()} + fields = ["author"] + widgets = {"author": forms.RadioSelect()} - writer = Writer.objects.create(name='Joe Doe') + writer = Writer.objects.create(name="Joe Doe") form = BookForm() - self.assertEqual(list(form.fields['author'].choices), [ - ('', '---------'), - (writer.pk, 'Joe Doe'), - ]) + self.assertEqual( + list(form.fields["author"].choices), + [ + ("", "---------"), + (writer.pk, "Joe Doe"), + ], + ) def test_non_blank_foreign_key_with_radio(self): class AwardForm(forms.ModelForm): class Meta: model = Award - fields = ['character'] - widgets = {'character': forms.RadioSelect()} + fields = ["character"] + widgets = {"character": forms.RadioSelect()} character = Character.objects.create( - username='user', + username="user", last_action=datetime.datetime.today(), ) form = AwardForm() self.assertEqual( - list(form.fields['character'].choices), - [(character.pk, 'user')], + list(form.fields["character"].choices), + [(character.pk, "user")], ) def test_save_blank_false_with_required_false(self): @@ -295,20 +353,24 @@ class ModelFormBaseTest(TestCase): A ModelForm with a model with a field set to blank=False and the form field set to required=False should allow the field to be unset. """ - obj = Writer.objects.create(name='test') - form = CustomWriterForm(data={'name': ''}, instance=obj) + obj = Writer.objects.create(name="test") + form = CustomWriterForm(data={"name": ""}, instance=obj) self.assertTrue(form.is_valid()) obj = form.save() - self.assertEqual(obj.name, '') + self.assertEqual(obj.name, "") def test_save_blank_null_unique_charfield_saves_null(self): - form_class = modelform_factory(model=NullableUniqueCharFieldModel, fields='__all__') - empty_value = '' if connection.features.interprets_empty_strings_as_nulls else None + form_class = modelform_factory( + model=NullableUniqueCharFieldModel, fields="__all__" + ) + empty_value = ( + "" if connection.features.interprets_empty_strings_as_nulls else None + ) data = { - 'codename': '', - 'email': '', - 'slug': '', - 'url': '', + "codename": "", + "email": "", + "slug": "", + "url": "", } form = form_class(data=data) self.assertTrue(form.is_valid()) @@ -334,6 +396,7 @@ class ModelFormBaseTest(TestCase): "MissingFieldsForm needs updating." ) with self.assertRaisesMessage(ImproperlyConfigured, message): + class MissingFieldsForm(forms.ModelForm): class Meta: model = Category @@ -342,31 +405,37 @@ class ModelFormBaseTest(TestCase): class ExtraFields(BaseCategoryForm): some_extra_field = forms.BooleanField() - self.assertEqual(list(ExtraFields.base_fields), - ['name', 'slug', 'url', 'some_extra_field']) + self.assertEqual( + list(ExtraFields.base_fields), ["name", "slug", "url", "some_extra_field"] + ) def test_extra_field_model_form(self): - with self.assertRaisesMessage(FieldError, 'no-field'): + with self.assertRaisesMessage(FieldError, "no-field"): + class ExtraPersonForm(forms.ModelForm): - """ ModelForm with an extra field """ + """ModelForm with an extra field""" + age = forms.IntegerField() class Meta: model = Person - fields = ('name', 'no-field') + fields = ("name", "no-field") def test_extra_declared_field_model_form(self): class ExtraPersonForm(forms.ModelForm): - """ ModelForm with an extra field """ + """ModelForm with an extra field""" + age = forms.IntegerField() class Meta: model = Person - fields = ('name', 'age') + fields = ("name", "age") def test_extra_field_modelform_factory(self): - with self.assertRaisesMessage(FieldError, 'Unknown field(s) (no-field) specified for Person'): - modelform_factory(Person, fields=['no-field', 'name']) + with self.assertRaisesMessage( + FieldError, "Unknown field(s) (no-field) specified for Person" + ): + modelform_factory(Person, fields=["no-field", "name"]) def test_replace_field(self): class ReplaceField(forms.ModelForm): @@ -374,9 +443,11 @@ class ModelFormBaseTest(TestCase): class Meta: model = Category - fields = '__all__' + fields = "__all__" - self.assertIsInstance(ReplaceField.base_fields['url'], forms.fields.BooleanField) + self.assertIsInstance( + ReplaceField.base_fields["url"], forms.fields.BooleanField + ) def test_replace_field_variant_2(self): # Should have the same result as before, @@ -386,9 +457,11 @@ class ModelFormBaseTest(TestCase): class Meta: model = Category - fields = ['url'] + fields = ["url"] - self.assertIsInstance(ReplaceField.base_fields['url'], forms.fields.BooleanField) + self.assertIsInstance( + ReplaceField.base_fields["url"], forms.fields.BooleanField + ) def test_replace_field_variant_3(self): # Should have the same result as before, @@ -400,7 +473,9 @@ class ModelFormBaseTest(TestCase): model = Category fields = [] # url will still appear, since it is explicit above - self.assertIsInstance(ReplaceField.base_fields['url'], forms.fields.BooleanField) + self.assertIsInstance( + ReplaceField.base_fields["url"], forms.fields.BooleanField + ) def test_override_field(self): class WriterForm(forms.ModelForm): @@ -408,50 +483,53 @@ class ModelFormBaseTest(TestCase): class Meta: model = Writer - fields = '__all__' + fields = "__all__" - wf = WriterForm({'name': 'Richard Lockridge'}) + wf = WriterForm({"name": "Richard Lockridge"}) self.assertTrue(wf.is_valid()) def test_limit_nonexistent_field(self): - expected_msg = 'Unknown field(s) (nonexistent) specified for Category' + expected_msg = "Unknown field(s) (nonexistent) specified for Category" with self.assertRaisesMessage(FieldError, expected_msg): + class InvalidCategoryForm(forms.ModelForm): class Meta: model = Category - fields = ['nonexistent'] + fields = ["nonexistent"] def test_limit_fields_with_string(self): expected_msg = "CategoryForm.Meta.fields cannot be a string. Did you mean to type: ('url',)?" with self.assertRaisesMessage(TypeError, expected_msg): + class CategoryForm(forms.ModelForm): class Meta: model = Category - fields = ('url') # note the missing comma + fields = "url" # note the missing comma def test_exclude_fields(self): class ExcludeFields(forms.ModelForm): class Meta: model = Category - exclude = ['url'] + exclude = ["url"] - self.assertEqual(list(ExcludeFields.base_fields), ['name', 'slug']) + self.assertEqual(list(ExcludeFields.base_fields), ["name", "slug"]) def test_exclude_nonexistent_field(self): class ExcludeFields(forms.ModelForm): class Meta: model = Category - exclude = ['nonexistent'] + exclude = ["nonexistent"] - self.assertEqual(list(ExcludeFields.base_fields), ['name', 'slug', 'url']) + self.assertEqual(list(ExcludeFields.base_fields), ["name", "slug", "url"]) def test_exclude_fields_with_string(self): expected_msg = "CategoryForm.Meta.exclude cannot be a string. Did you mean to type: ('url',)?" with self.assertRaisesMessage(TypeError, expected_msg): + class CategoryForm(forms.ModelForm): class Meta: model = Category - exclude = ('url') # note the missing comma + exclude = "url" # note the missing comma def test_exclude_and_validation(self): # This Price instance generated by this form is not valid because the quantity @@ -460,9 +538,9 @@ class ModelFormBaseTest(TestCase): class PriceFormWithoutQuantity(forms.ModelForm): class Meta: model = Price - exclude = ('quantity',) + exclude = ("quantity",) - form = PriceFormWithoutQuantity({'price': '6.00'}) + form = PriceFormWithoutQuantity({"price": "6.00"}) self.assertTrue(form.is_valid()) price = form.save(commit=False) msg = "{'quantity': ['This field cannot be null.']}" @@ -474,52 +552,71 @@ class ModelFormBaseTest(TestCase): class PriceFormWithoutQuantity(forms.ModelForm): class Meta: model = Price - fields = ('price',) - form = PriceFormWithoutQuantity({'price': '6.00'}) + fields = ("price",) + + form = PriceFormWithoutQuantity({"price": "6.00"}) self.assertTrue(form.is_valid()) # The form should still have an instance of a model that is not complete and # not saved into a DB yet. - self.assertEqual(form.instance.price, Decimal('6.00')) + self.assertEqual(form.instance.price, Decimal("6.00")) self.assertIsNone(form.instance.quantity) self.assertIsNone(form.instance.pk) def test_confused_form(self): class ConfusedForm(forms.ModelForm): - """ Using 'fields' *and* 'exclude'. Not sure why you'd want to do + """Using 'fields' *and* 'exclude'. Not sure why you'd want to do this, but uh, "be liberal in what you accept" and all. """ + class Meta: model = Category - fields = ['name', 'url'] - exclude = ['url'] + fields = ["name", "url"] + exclude = ["url"] - self.assertEqual(list(ConfusedForm.base_fields), - ['name']) + self.assertEqual(list(ConfusedForm.base_fields), ["name"]) def test_mixmodel_form(self): class MixModelForm(BaseCategoryForm): - """ Don't allow more than one 'model' definition in the + """Don't allow more than one 'model' definition in the inheritance hierarchy. Technically, it would generate a valid form, but the fact that the resulting save method won't deal with multiple objects is likely to trip up people not familiar with the mechanics. """ + class Meta: model = Article - fields = '__all__' + fields = "__all__" + # MixModelForm is now an Article-related thing, because MixModelForm.Meta # overrides BaseCategoryForm.Meta. self.assertEqual( list(MixModelForm.base_fields), - ['headline', 'slug', 'pub_date', 'writer', 'article', 'categories', 'status'] + [ + "headline", + "slug", + "pub_date", + "writer", + "article", + "categories", + "status", + ], ) def test_article_form(self): self.assertEqual( list(ArticleForm.base_fields), - ['headline', 'slug', 'pub_date', 'writer', 'article', 'categories', 'status'] + [ + "headline", + "slug", + "pub_date", + "writer", + "article", + "categories", + "status", + ], ) def test_bad_form(self): @@ -529,7 +626,15 @@ class ModelFormBaseTest(TestCase): self.assertEqual( list(BadForm.base_fields), - ['headline', 'slug', 'pub_date', 'writer', 'article', 'categories', 'status'] + [ + "headline", + "slug", + "pub_date", + "writer", + "article", + "categories", + "status", + ], ) def test_invalid_meta_model(self): @@ -538,7 +643,7 @@ class ModelFormBaseTest(TestCase): pass # no model # Can't create new form - msg = 'ModelForm has no model class specified.' + msg = "ModelForm has no model class specified." with self.assertRaisesMessage(ValueError, msg): InvalidModelForm() @@ -548,13 +653,14 @@ class ModelFormBaseTest(TestCase): def test_subcategory_form(self): class SubCategoryForm(BaseCategoryForm): - """ Subclassing without specifying a Meta on the class will use + """Subclassing without specifying a Meta on the class will use the parent's Meta (or the first parent in the MRO if there are multiple parent classes). """ + pass - self.assertEqual(list(SubCategoryForm.base_fields), ['name', 'slug', 'url']) + self.assertEqual(list(SubCategoryForm.base_fields), ["name", "slug", "url"]) def test_subclassmeta_form(self): class SomeCategoryForm(forms.ModelForm): @@ -562,14 +668,15 @@ class ModelFormBaseTest(TestCase): class Meta: model = Category - fields = '__all__' + fields = "__all__" class SubclassMeta(SomeCategoryForm): - """ We can also subclass the Meta inner class to change the fields + """We can also subclass the Meta inner class to change the fields list. """ + class Meta(SomeCategoryForm.Meta): - exclude = ['url'] + exclude = ["url"] self.assertHTMLEqual( str(SubclassMeta()), @@ -578,33 +685,32 @@ class ModelFormBaseTest(TestCase): <tr><th><label for="id_slug">Slug:</label></th> <td><input id="id_slug" type="text" name="slug" maxlength="20" required></td></tr> <tr><th><label for="id_checkbox">Checkbox:</label></th> -<td><input type="checkbox" name="checkbox" id="id_checkbox" required></td></tr>""" +<td><input type="checkbox" name="checkbox" id="id_checkbox" required></td></tr>""", ) def test_orderfields_form(self): class OrderFields(forms.ModelForm): class Meta: model = Category - fields = ['url', 'name'] + fields = ["url", "name"] - self.assertEqual(list(OrderFields.base_fields), - ['url', 'name']) + self.assertEqual(list(OrderFields.base_fields), ["url", "name"]) self.assertHTMLEqual( str(OrderFields()), """<tr><th><label for="id_url">The URL:</label></th> <td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr> <tr><th><label for="id_name">Name:</label></th> -<td><input id="id_name" type="text" name="name" maxlength="20" required></td></tr>""" +<td><input id="id_name" type="text" name="name" maxlength="20" required></td></tr>""", ) def test_orderfields2_form(self): class OrderFields2(forms.ModelForm): class Meta: model = Category - fields = ['slug', 'url', 'name'] - exclude = ['url'] + fields = ["slug", "url", "name"] + exclude = ["url"] - self.assertEqual(list(OrderFields2.base_fields), ['slug', 'name']) + self.assertEqual(list(OrderFields2.base_fields), ["slug", "name"]) def test_default_populated_on_optional_field(self): class PubForm(forms.ModelForm): @@ -612,20 +718,20 @@ class ModelFormBaseTest(TestCase): class Meta: model = PublicationDefaults - fields = ('mode',) + fields = ("mode",) # Empty data uses the model field default. mf1 = PubForm({}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) - self.assertEqual(m1.mode, 'di') - self.assertEqual(m1._meta.get_field('mode').get_default(), 'di') + self.assertEqual(m1.mode, "di") + self.assertEqual(m1._meta.get_field("mode").get_default(), "di") # Blank data doesn't use the model field default. - mf2 = PubForm({'mode': ''}) + mf2 = PubForm({"mode": ""}) self.assertEqual(mf2.errors, {}) m2 = mf2.save(commit=False) - self.assertEqual(m2.mode, '') + self.assertEqual(m2.mode, "") def test_default_not_populated_on_non_empty_value_in_cleaned_data(self): class PubForm(forms.ModelForm): @@ -633,20 +739,20 @@ class ModelFormBaseTest(TestCase): mocked_mode = None def clean(self): - self.cleaned_data['mode'] = self.mocked_mode + self.cleaned_data["mode"] = self.mocked_mode return self.cleaned_data class Meta: model = PublicationDefaults - fields = ('mode',) + fields = ("mode",) pub_form = PubForm({}) - pub_form.mocked_mode = 'de' + pub_form.mocked_mode = "de" pub = pub_form.save(commit=False) - self.assertEqual(pub.mode, 'de') + self.assertEqual(pub.mode, "de") # Default should be populated on an empty value in cleaned_data. - default_mode = 'di' - for empty_value in pub_form.fields['mode'].empty_values: + default_mode = "di" + for empty_value in pub_form.fields["mode"].empty_values: with self.subTest(empty_value=empty_value): pub_form = PubForm({}) pub_form.mocked_mode = empty_value @@ -657,7 +763,7 @@ class ModelFormBaseTest(TestCase): class PubForm(forms.ModelForm): class Meta: model = PublicationDefaults - fields = ('active',) + fields = ("active",) # Empty data doesn't use the model default because CheckboxInput # doesn't have a value in HTML form submission. @@ -665,8 +771,8 @@ class ModelFormBaseTest(TestCase): self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) self.assertIs(m1.active, False) - self.assertIsInstance(mf1.fields['active'].widget, forms.CheckboxInput) - self.assertIs(m1._meta.get_field('active').get_default(), True) + self.assertIsInstance(mf1.fields["active"].widget, forms.CheckboxInput) + self.assertIs(m1._meta.get_field("active").get_default(), True) def test_default_not_populated_on_checkboxselectmultiple(self): class PubForm(forms.ModelForm): @@ -674,15 +780,15 @@ class ModelFormBaseTest(TestCase): class Meta: model = PublicationDefaults - fields = ('mode',) + fields = ("mode",) # Empty data doesn't use the model default because an unchecked # CheckboxSelectMultiple doesn't have a value in HTML form submission. mf1 = PubForm({}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) - self.assertEqual(m1.mode, '') - self.assertEqual(m1._meta.get_field('mode').get_default(), 'di') + self.assertEqual(m1.mode, "") + self.assertEqual(m1._meta.get_field("mode").get_default(), "di") def test_default_not_populated_on_selectmultiple(self): class PubForm(forms.ModelForm): @@ -690,28 +796,30 @@ class ModelFormBaseTest(TestCase): class Meta: model = PublicationDefaults - fields = ('mode',) + fields = ("mode",) # Empty data doesn't use the model default because an unselected # SelectMultiple doesn't have a value in HTML form submission. mf1 = PubForm({}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) - self.assertEqual(m1.mode, '') - self.assertEqual(m1._meta.get_field('mode').get_default(), 'di') + self.assertEqual(m1.mode, "") + self.assertEqual(m1._meta.get_field("mode").get_default(), "di") def test_prefixed_form_with_default_field(self): class PubForm(forms.ModelForm): - prefix = 'form-prefix' + prefix = "form-prefix" class Meta: model = PublicationDefaults - fields = ('mode',) + fields = ("mode",) - mode = 'de' - self.assertNotEqual(mode, PublicationDefaults._meta.get_field('mode').get_default()) + mode = "de" + self.assertNotEqual( + mode, PublicationDefaults._meta.get_field("mode").get_default() + ) - mf1 = PubForm({'form-prefix-mode': mode}) + mf1 = PubForm({"form-prefix-mode": mode}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) self.assertEqual(m1.mode, mode) @@ -726,14 +834,16 @@ class ModelFormBaseTest(TestCase): class Meta: model = PublicationDefaults - fields = ('datetime_published',) + fields = ("datetime_published",) mf1 = PubForm({}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) self.assertEqual(m1.datetime_published, datetime.datetime(2000, 1, 1)) - mf2 = PubForm({'datetime_published_0': '2010-01-01', 'datetime_published_1': '0:00:00'}) + mf2 = PubForm( + {"datetime_published_0": "2010-01-01", "datetime_published_1": "0:00:00"} + ) self.assertEqual(mf2.errors, {}) m2 = mf2.save(commit=False) self.assertEqual(m2.datetime_published, datetime.datetime(2010, 1, 1)) @@ -742,32 +852,40 @@ class ModelFormBaseTest(TestCase): class PubForm(forms.ModelForm): class Meta: model = PublicationDefaults - fields = ('file',) + fields = ("file",) mf1 = PubForm({}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) - self.assertEqual(m1.file.name, 'default.txt') + self.assertEqual(m1.file.name, "default.txt") - mf2 = PubForm({}, {'file': SimpleUploadedFile('name', b'foo')}) + mf2 = PubForm({}, {"file": SimpleUploadedFile("name", b"foo")}) self.assertEqual(mf2.errors, {}) m2 = mf2.save(commit=False) - self.assertEqual(m2.file.name, 'name') + self.assertEqual(m2.file.name, "name") def test_default_selectdatewidget(self): class PubForm(forms.ModelForm): - date_published = forms.DateField(required=False, widget=forms.SelectDateWidget) + date_published = forms.DateField( + required=False, widget=forms.SelectDateWidget + ) class Meta: model = PublicationDefaults - fields = ('date_published',) + fields = ("date_published",) mf1 = PubForm({}) self.assertEqual(mf1.errors, {}) m1 = mf1.save(commit=False) self.assertEqual(m1.date_published, datetime.date.today()) - mf2 = PubForm({'date_published_year': '2010', 'date_published_month': '1', 'date_published_day': '1'}) + mf2 = PubForm( + { + "date_published_year": "2010", + "date_published_month": "1", + "date_published_day": "1", + } + ) self.assertEqual(mf2.errors, {}) m2 = mf2.save(commit=False) self.assertEqual(m2.date_published, datetime.date(2010, 1, 1)) @@ -776,27 +894,27 @@ class ModelFormBaseTest(TestCase): class FieldOverridesByFormMetaForm(forms.ModelForm): class Meta: model = Category - fields = ['name', 'url', 'slug'] + fields = ["name", "url", "slug"] widgets = { - 'name': forms.Textarea, - 'url': forms.TextInput(attrs={'class': 'url'}) + "name": forms.Textarea, + "url": forms.TextInput(attrs={"class": "url"}), } labels = { - 'name': 'Title', + "name": "Title", } help_texts = { - 'slug': 'Watch out! Letters, numbers, underscores and hyphens only.', + "slug": "Watch out! Letters, numbers, underscores and hyphens only.", } error_messages = { - 'slug': { - 'invalid': ( + "slug": { + "invalid": ( "Didn't you read the help text? " "We said letters, numbers, underscores and hyphens only!" ) } } field_classes = { - 'url': forms.URLField, + "url": forms.URLField, } @@ -804,70 +922,72 @@ class TestFieldOverridesByFormMeta(SimpleTestCase): def test_widget_overrides(self): form = FieldOverridesByFormMetaForm() self.assertHTMLEqual( - str(form['name']), + str(form["name"]), '<textarea id="id_name" rows="10" cols="40" name="name" maxlength="20" required></textarea>', ) self.assertHTMLEqual( - str(form['url']), + str(form["url"]), '<input id="id_url" type="text" class="url" name="url" maxlength="40" required>', ) self.assertHTMLEqual( - str(form['slug']), + str(form["slug"]), '<input id="id_slug" type="text" name="slug" maxlength="20" required>', ) def test_label_overrides(self): form = FieldOverridesByFormMetaForm() self.assertHTMLEqual( - str(form['name'].label_tag()), + str(form["name"].label_tag()), '<label for="id_name">Title:</label>', ) self.assertHTMLEqual( - str(form['url'].label_tag()), + str(form["url"].label_tag()), '<label for="id_url">The URL:</label>', ) self.assertHTMLEqual( - str(form['slug'].label_tag()), + str(form["slug"].label_tag()), '<label for="id_slug">Slug:</label>', ) self.assertHTMLEqual( - form['name'].legend_tag(), + form["name"].legend_tag(), '<legend for="id_name">Title:</legend>', ) self.assertHTMLEqual( - form['url'].legend_tag(), + form["url"].legend_tag(), '<legend for="id_url">The URL:</legend>', ) self.assertHTMLEqual( - form['slug'].legend_tag(), + form["slug"].legend_tag(), '<legend for="id_slug">Slug:</legend>', ) def test_help_text_overrides(self): form = FieldOverridesByFormMetaForm() self.assertEqual( - form['slug'].help_text, - 'Watch out! Letters, numbers, underscores and hyphens only.', + form["slug"].help_text, + "Watch out! Letters, numbers, underscores and hyphens only.", ) def test_error_messages_overrides(self): - form = FieldOverridesByFormMetaForm(data={ - 'name': 'Category', - 'url': 'http://www.example.com/category/', - 'slug': '!%#*@', - }) + form = FieldOverridesByFormMetaForm( + data={ + "name": "Category", + "url": "http://www.example.com/category/", + "slug": "!%#*@", + } + ) form.full_clean() error = [ "Didn't you read the help text? " "We said letters, numbers, underscores and hyphens only!", ] - self.assertEqual(form.errors, {'slug': error}) + self.assertEqual(form.errors, {"slug": error}) def test_field_type_overrides(self): form = FieldOverridesByFormMetaForm() - self.assertIs(Category._meta.get_field('url').__class__, models.CharField) - self.assertIsInstance(form.fields['url'], forms.URLField) + self.assertIs(Category._meta.get_field("url").__class__, models.CharField) + self.assertIsInstance(form.fields["url"], forms.URLField) class IncompleteCategoryFormWithFields(forms.ModelForm): @@ -875,10 +995,11 @@ class IncompleteCategoryFormWithFields(forms.ModelForm): A form that replaces the model's url field with a custom one. This should prevent the model field's validation from being called. """ + url = forms.CharField(required=False) class Meta: - fields = ('name', 'slug') + fields = ("name", "slug") model = Category @@ -887,20 +1008,25 @@ class IncompleteCategoryFormWithExclude(forms.ModelForm): A form that replaces the model's url field with a custom one. This should prevent the model field's validation from being called. """ + url = forms.CharField(required=False) class Meta: - exclude = ['url'] + exclude = ["url"] model = Category class ValidationTest(SimpleTestCase): def test_validates_with_replaced_field_not_specified(self): - form = IncompleteCategoryFormWithFields(data={'name': 'some name', 'slug': 'some-slug'}) + form = IncompleteCategoryFormWithFields( + data={"name": "some name", "slug": "some-slug"} + ) self.assertIs(form.is_valid(), True) def test_validates_with_replaced_field_excluded(self): - form = IncompleteCategoryFormWithExclude(data={'name': 'some name', 'slug': 'some-slug'}) + form = IncompleteCategoryFormWithExclude( + data={"name": "some name", "slug": "some-slug"} + ) self.assertIs(form.is_valid(), True) def test_notrequired_overrides_notblank(self): @@ -912,29 +1038,35 @@ class UniqueTest(TestCase): """ unique/unique_together validation. """ + @classmethod def setUpTestData(cls): - cls.writer = Writer.objects.create(name='Mike Royko') + cls.writer = Writer.objects.create(name="Mike Royko") def test_simple_unique(self): - form = ProductForm({'slug': 'teddy-bear-blue'}) + form = ProductForm({"slug": "teddy-bear-blue"}) self.assertTrue(form.is_valid()) obj = form.save() - form = ProductForm({'slug': 'teddy-bear-blue'}) + form = ProductForm({"slug": "teddy-bear-blue"}) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['slug'], ['Product with this Slug already exists.']) - form = ProductForm({'slug': 'teddy-bear-blue'}, instance=obj) + self.assertEqual( + form.errors["slug"], ["Product with this Slug already exists."] + ) + form = ProductForm({"slug": "teddy-bear-blue"}, instance=obj) self.assertTrue(form.is_valid()) def test_unique_together(self): """ModelForm test of unique_together constraint""" - form = PriceForm({'price': '6.00', 'quantity': '1'}) + form = PriceForm({"price": "6.00", "quantity": "1"}) self.assertTrue(form.is_valid()) form.save() - form = PriceForm({'price': '6.00', 'quantity': '1'}) + form = PriceForm({"price": "6.00", "quantity": "1"}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['__all__'], ['Price with this Price and Quantity already exists.']) + self.assertEqual( + form.errors["__all__"], + ["Price with this Price and Quantity already exists."], + ) def test_unique_together_exclusion(self): """ @@ -943,16 +1075,17 @@ class UniqueTest(TestCase): form.save(commit=False) and then assigning the missing field(s) to the model instance. """ + class BookForm(forms.ModelForm): class Meta: model = DerivedBook - fields = ('isbn', 'suffix1') + fields = ("isbn", "suffix1") # The unique_together is on suffix1/suffix2 but only suffix1 is part # of the form. The fields must have defaults, otherwise they'll be # skipped by other logic. - self.assertEqual(DerivedBook._meta.unique_together, (('suffix1', 'suffix2'),)) - for name in ('suffix1', 'suffix2'): + self.assertEqual(DerivedBook._meta.unique_together, (("suffix1", "suffix2"),)) + for name in ("suffix1", "suffix2"): with self.subTest(name=name): field = DerivedBook._meta.get_field(name) self.assertEqual(field.default, 0) @@ -960,8 +1093,8 @@ class UniqueTest(TestCase): # The form fails validation with "Derived book with this Suffix1 and # Suffix2 already exists." if the unique_together validation isn't # skipped. - DerivedBook.objects.create(isbn='12345') - form = BookForm({'isbn': '56789', 'suffix1': '0'}) + DerivedBook.objects.create(isbn="12345") + form = BookForm({"isbn": "56789", "suffix1": "0"}) self.assertTrue(form.is_valid(), form.errors) def test_multiple_field_unique_together(self): @@ -971,131 +1104,176 @@ class UniqueTest(TestCase): before doing all the validation checking (not just failing after the first one). """ + class TripleForm(forms.ModelForm): class Meta: model = Triple - fields = '__all__' + fields = "__all__" Triple.objects.create(left=1, middle=2, right=3) - form = TripleForm({'left': '1', 'middle': '2', 'right': '3'}) + form = TripleForm({"left": "1", "middle": "2", "right": "3"}) self.assertFalse(form.is_valid()) - form = TripleForm({'left': '1', 'middle': '3', 'right': '1'}) + form = TripleForm({"left": "1", "middle": "3", "right": "1"}) self.assertTrue(form.is_valid()) - @skipUnlessDBFeature('supports_nullable_unique_constraints') + @skipUnlessDBFeature("supports_nullable_unique_constraints") def test_unique_null(self): - title = 'I May Be Wrong But I Doubt It' - form = BookForm({'title': title, 'author': self.writer.pk}) + title = "I May Be Wrong But I Doubt It" + form = BookForm({"title": title, "author": self.writer.pk}) self.assertTrue(form.is_valid()) form.save() - form = BookForm({'title': title, 'author': self.writer.pk}) + form = BookForm({"title": title, "author": self.writer.pk}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['__all__'], ['Book with this Title and Author already exists.']) - form = BookForm({'title': title}) + self.assertEqual( + form.errors["__all__"], ["Book with this Title and Author already exists."] + ) + form = BookForm({"title": title}) self.assertTrue(form.is_valid()) form.save() - form = BookForm({'title': title}) + form = BookForm({"title": title}) self.assertTrue(form.is_valid()) def test_inherited_unique(self): - title = 'Boss' + title = "Boss" Book.objects.create(title=title, author=self.writer, special_id=1) - form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'special_id': '1', 'isbn': '12345'}) + form = DerivedBookForm( + { + "title": "Other", + "author": self.writer.pk, + "special_id": "1", + "isbn": "12345", + } + ) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['special_id'], ['Book with this Special id already exists.']) + self.assertEqual( + form.errors["special_id"], ["Book with this Special id already exists."] + ) def test_inherited_unique_together(self): - title = 'Boss' - form = BookForm({'title': title, 'author': self.writer.pk}) + title = "Boss" + form = BookForm({"title": title, "author": self.writer.pk}) self.assertTrue(form.is_valid()) form.save() - form = DerivedBookForm({'title': title, 'author': self.writer.pk, 'isbn': '12345'}) + form = DerivedBookForm( + {"title": title, "author": self.writer.pk, "isbn": "12345"} + ) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['__all__'], ['Book with this Title and Author already exists.']) + self.assertEqual( + form.errors["__all__"], ["Book with this Title and Author already exists."] + ) def test_abstract_inherited_unique(self): - title = 'Boss' - isbn = '12345' + title = "Boss" + isbn = "12345" DerivedBook.objects.create(title=title, author=self.writer, isbn=isbn) - form = DerivedBookForm({ - 'title': 'Other', 'author': self.writer.pk, 'isbn': isbn, - 'suffix1': '1', 'suffix2': '2', - }) + form = DerivedBookForm( + { + "title": "Other", + "author": self.writer.pk, + "isbn": isbn, + "suffix1": "1", + "suffix2": "2", + } + ) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['isbn'], ['Derived book with this Isbn already exists.']) + self.assertEqual( + form.errors["isbn"], ["Derived book with this Isbn already exists."] + ) def test_abstract_inherited_unique_together(self): - title = 'Boss' - isbn = '12345' + title = "Boss" + isbn = "12345" DerivedBook.objects.create(title=title, author=self.writer, isbn=isbn) - form = DerivedBookForm({ - 'title': 'Other', - 'author': self.writer.pk, - 'isbn': '9876', - 'suffix1': '0', - 'suffix2': '0' - }) + form = DerivedBookForm( + { + "title": "Other", + "author": self.writer.pk, + "isbn": "9876", + "suffix1": "0", + "suffix2": "0", + } + ) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) self.assertEqual( - form.errors['__all__'], - ['Derived book with this Suffix1 and Suffix2 already exists.'], + form.errors["__all__"], + ["Derived book with this Suffix1 and Suffix2 already exists."], ) def test_explicitpk_unspecified(self): """Test for primary_key being in the form and failing validation.""" - form = ExplicitPKForm({'key': '', 'desc': ''}) + form = ExplicitPKForm({"key": "", "desc": ""}) self.assertFalse(form.is_valid()) def test_explicitpk_unique(self): """Ensure keys and blank character strings are tested for uniqueness.""" - form = ExplicitPKForm({'key': 'key1', 'desc': ''}) + form = ExplicitPKForm({"key": "key1", "desc": ""}) self.assertTrue(form.is_valid()) form.save() - form = ExplicitPKForm({'key': 'key1', 'desc': ''}) + form = ExplicitPKForm({"key": "key1", "desc": ""}) self.assertFalse(form.is_valid()) if connection.features.interprets_empty_strings_as_nulls: self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['key'], ['Explicit pk with this Key already exists.']) + self.assertEqual( + form.errors["key"], ["Explicit pk with this Key already exists."] + ) else: self.assertEqual(len(form.errors), 3) - self.assertEqual(form.errors['__all__'], ['Explicit pk with this Key and Desc already exists.']) - self.assertEqual(form.errors['desc'], ['Explicit pk with this Desc already exists.']) - self.assertEqual(form.errors['key'], ['Explicit pk with this Key already exists.']) + self.assertEqual( + form.errors["__all__"], + ["Explicit pk with this Key and Desc already exists."], + ) + self.assertEqual( + form.errors["desc"], ["Explicit pk with this Desc already exists."] + ) + self.assertEqual( + form.errors["key"], ["Explicit pk with this Key already exists."] + ) def test_unique_for_date(self): p = Post.objects.create( - title="Django 1.0 is released", slug="Django 1.0", - subtitle="Finally", posted=datetime.date(2008, 9, 3), + title="Django 1.0 is released", + slug="Django 1.0", + subtitle="Finally", + posted=datetime.date(2008, 9, 3), ) - form = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'}) + form = PostForm({"title": "Django 1.0 is released", "posted": "2008-09-03"}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['title'], ['Title must be unique for Posted date.']) - form = PostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'}) + self.assertEqual( + form.errors["title"], ["Title must be unique for Posted date."] + ) + form = PostForm({"title": "Work on Django 1.1 begins", "posted": "2008-09-03"}) self.assertTrue(form.is_valid()) - form = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'}) + form = PostForm({"title": "Django 1.0 is released", "posted": "2008-09-04"}) self.assertTrue(form.is_valid()) - form = PostForm({'slug': "Django 1.0", 'posted': '2008-01-01'}) + form = PostForm({"slug": "Django 1.0", "posted": "2008-01-01"}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['slug'], ['Slug must be unique for Posted year.']) - form = PostForm({'subtitle': "Finally", 'posted': '2008-09-30'}) + self.assertEqual(form.errors["slug"], ["Slug must be unique for Posted year."]) + form = PostForm({"subtitle": "Finally", "posted": "2008-09-30"}) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors['subtitle'], ['Subtitle must be unique for Posted month.']) - data = {'subtitle': "Finally", "title": "Django 1.0 is released", "slug": "Django 1.0", 'posted': '2008-09-03'} + self.assertEqual( + form.errors["subtitle"], ["Subtitle must be unique for Posted month."] + ) + data = { + "subtitle": "Finally", + "title": "Django 1.0 is released", + "slug": "Django 1.0", + "posted": "2008-09-03", + } form = PostForm(data, instance=p) self.assertTrue(form.is_valid()) - form = PostForm({'title': "Django 1.0 is released"}) + form = PostForm({"title": "Django 1.0 is released"}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['posted'], ['This field is required.']) + self.assertEqual(form.errors["posted"], ["This field is required."]) def test_unique_for_date_in_exclude(self): """ @@ -1103,46 +1281,68 @@ class UniqueTest(TestCase): ModelForm (in this case 'posted' has editable=False, then the constraint should be ignored. """ + class DateTimePostForm(forms.ModelForm): class Meta: model = DateTimePost - fields = '__all__' + fields = "__all__" DateTimePost.objects.create( - title="Django 1.0 is released", slug="Django 1.0", - subtitle="Finally", posted=datetime.datetime(2008, 9, 3, 10, 10, 1), + title="Django 1.0 is released", + slug="Django 1.0", + subtitle="Finally", + posted=datetime.datetime(2008, 9, 3, 10, 10, 1), ) # 'title' has unique_for_date='posted' - form = DateTimePostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'}) + form = DateTimePostForm( + {"title": "Django 1.0 is released", "posted": "2008-09-03"} + ) self.assertTrue(form.is_valid()) # 'slug' has unique_for_year='posted' - form = DateTimePostForm({'slug': "Django 1.0", 'posted': '2008-01-01'}) + form = DateTimePostForm({"slug": "Django 1.0", "posted": "2008-01-01"}) self.assertTrue(form.is_valid()) # 'subtitle' has unique_for_month='posted' - form = DateTimePostForm({'subtitle': "Finally", 'posted': '2008-09-30'}) + form = DateTimePostForm({"subtitle": "Finally", "posted": "2008-09-30"}) self.assertTrue(form.is_valid()) def test_inherited_unique_for_date(self): p = Post.objects.create( - title="Django 1.0 is released", slug="Django 1.0", - subtitle="Finally", posted=datetime.date(2008, 9, 3), + title="Django 1.0 is released", + slug="Django 1.0", + subtitle="Finally", + posted=datetime.date(2008, 9, 3), + ) + form = DerivedPostForm( + {"title": "Django 1.0 is released", "posted": "2008-09-03"} ) - form = DerivedPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['title'], ['Title must be unique for Posted date.']) - form = DerivedPostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'}) + self.assertEqual( + form.errors["title"], ["Title must be unique for Posted date."] + ) + form = DerivedPostForm( + {"title": "Work on Django 1.1 begins", "posted": "2008-09-03"} + ) self.assertTrue(form.is_valid()) - form = DerivedPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'}) + form = DerivedPostForm( + {"title": "Django 1.0 is released", "posted": "2008-09-04"} + ) self.assertTrue(form.is_valid()) - form = DerivedPostForm({'slug': "Django 1.0", 'posted': '2008-01-01'}) + form = DerivedPostForm({"slug": "Django 1.0", "posted": "2008-01-01"}) self.assertFalse(form.is_valid()) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['slug'], ['Slug must be unique for Posted year.']) - form = DerivedPostForm({'subtitle': "Finally", 'posted': '2008-09-30'}) + self.assertEqual(form.errors["slug"], ["Slug must be unique for Posted year."]) + form = DerivedPostForm({"subtitle": "Finally", "posted": "2008-09-30"}) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors['subtitle'], ['Subtitle must be unique for Posted month.']) - data = {'subtitle': "Finally", "title": "Django 1.0 is released", "slug": "Django 1.0", 'posted': '2008-09-03'} + self.assertEqual( + form.errors["subtitle"], ["Subtitle must be unique for Posted month."] + ) + data = { + "subtitle": "Finally", + "title": "Django 1.0 is released", + "slug": "Django 1.0", + "posted": "2008-09-03", + } form = DerivedPostForm(data, instance=p) self.assertTrue(form.is_valid()) @@ -1150,20 +1350,26 @@ class UniqueTest(TestCase): class FlexDatePostForm(forms.ModelForm): class Meta: model = FlexibleDatePost - fields = '__all__' + fields = "__all__" p = FlexibleDatePost.objects.create( - title="Django 1.0 is released", slug="Django 1.0", - subtitle="Finally", posted=datetime.date(2008, 9, 3), + title="Django 1.0 is released", + slug="Django 1.0", + subtitle="Finally", + posted=datetime.date(2008, 9, 3), ) - form = FlexDatePostForm({'title': "Django 1.0 is released"}) + form = FlexDatePostForm({"title": "Django 1.0 is released"}) self.assertTrue(form.is_valid()) - form = FlexDatePostForm({'slug': "Django 1.0"}) + form = FlexDatePostForm({"slug": "Django 1.0"}) self.assertTrue(form.is_valid()) - form = FlexDatePostForm({'subtitle': "Finally"}) + form = FlexDatePostForm({"subtitle": "Finally"}) self.assertTrue(form.is_valid()) - data = {'subtitle': "Finally", "title": "Django 1.0 is released", "slug": "Django 1.0"} + data = { + "subtitle": "Finally", + "title": "Django 1.0 is released", + "slug": "Django 1.0", + } form = FlexDatePostForm(data, instance=p) self.assertTrue(form.is_valid()) @@ -1171,36 +1377,38 @@ class UniqueTest(TestCase): class CustomProductForm(ProductForm): class Meta(ProductForm.Meta): error_messages = { - 'slug': { - 'unique': "%(model_name)s's %(field_label)s not unique.", + "slug": { + "unique": "%(model_name)s's %(field_label)s not unique.", } } - Product.objects.create(slug='teddy-bear-blue') - form = CustomProductForm({'slug': 'teddy-bear-blue'}) + Product.objects.create(slug="teddy-bear-blue") + form = CustomProductForm({"slug": "teddy-bear-blue"}) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['slug'], ["Product's Slug not unique."]) + self.assertEqual(form.errors["slug"], ["Product's Slug not unique."]) def test_override_unique_together_message(self): class CustomPriceForm(PriceForm): class Meta(PriceForm.Meta): error_messages = { NON_FIELD_ERRORS: { - 'unique_together': "%(model_name)s's %(field_labels)s not unique.", + "unique_together": "%(model_name)s's %(field_labels)s not unique.", } } Price.objects.create(price=6.00, quantity=1) - form = CustomPriceForm({'price': '6.00', 'quantity': '1'}) + form = CustomPriceForm({"price": "6.00", "quantity": "1"}) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors[NON_FIELD_ERRORS], ["Price's Price and Quantity not unique."]) + self.assertEqual( + form.errors[NON_FIELD_ERRORS], ["Price's Price and Quantity not unique."] + ) def test_override_unique_for_date_message(self): class CustomPostForm(PostForm): class Meta(PostForm.Meta): error_messages = { - 'title': { - 'unique_for_date': ( + "title": { + "unique_for_date": ( "%(model_name)s's %(field_label)s not unique " "for %(date_field_label)s date." ), @@ -1208,21 +1416,33 @@ class UniqueTest(TestCase): } Post.objects.create( - title="Django 1.0 is released", slug="Django 1.0", - subtitle="Finally", posted=datetime.date(2008, 9, 3), + title="Django 1.0 is released", + slug="Django 1.0", + subtitle="Finally", + posted=datetime.date(2008, 9, 3), + ) + form = CustomPostForm( + {"title": "Django 1.0 is released", "posted": "2008-09-03"} ) - form = CustomPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'}) self.assertEqual(len(form.errors), 1) - self.assertEqual(form.errors['title'], ["Post's Title not unique for Posted date."]) + self.assertEqual( + form.errors["title"], ["Post's Title not unique for Posted date."] + ) class ModelFormBasicTests(TestCase): def create_basic_data(self): - self.c1 = Category.objects.create(name='Entertainment', slug='entertainment', url='entertainment') - self.c2 = Category.objects.create(name="It's a test", slug='its-test', url='test') - self.c3 = Category.objects.create(name='Third test', slug='third-test', url='third') - self.w_royko = Writer.objects.create(name='Mike Royko') - self.w_woodward = Writer.objects.create(name='Bob Woodward') + self.c1 = Category.objects.create( + name="Entertainment", slug="entertainment", url="entertainment" + ) + self.c2 = Category.objects.create( + name="It's a test", slug="its-test", url="test" + ) + self.c3 = Category.objects.create( + name="Third test", slug="third-test", url="third" + ) + self.w_royko = Writer.objects.create(name="Mike Royko") + self.w_woodward = Writer.objects.create(name="Bob Woodward") def test_base_form(self): self.assertEqual(Category.objects.count(), 0) @@ -1234,17 +1454,18 @@ class ModelFormBasicTests(TestCase): <tr><th><label for="id_slug">Slug:</label></th> <td><input id="id_slug" type="text" name="slug" maxlength="20" required></td></tr> <tr><th><label for="id_url">The URL:</label></th> -<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>""" +<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>""", ) self.assertHTMLEqual( str(f.as_ul()), """<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" maxlength="20" required></li> <li><label for="id_slug">Slug:</label> <input id="id_slug" type="text" name="slug" maxlength="20" required></li> -<li><label for="id_url">The URL:</label> <input id="id_url" type="text" name="url" maxlength="40" required></li>""" +<li><label for="id_url">The URL:</label> <input id="id_url" type="text" name="url" maxlength="40" required></li>""", ) self.assertHTMLEqual( str(f["name"]), - """<input id="id_name" type="text" name="name" maxlength="20" required>""") + """<input id="id_name" type="text" name="name" maxlength="20" required>""", + ) def test_auto_id(self): f = BaseCategoryForm(auto_id=False) @@ -1252,7 +1473,7 @@ class ModelFormBasicTests(TestCase): str(f.as_ul()), """<li>Name: <input type="text" name="name" maxlength="20" required></li> <li>Slug: <input type="text" name="slug" maxlength="20" required></li> -<li>The URL: <input type="text" name="url" maxlength="40" required></li>""" +<li>The URL: <input type="text" name="url" maxlength="40" required></li>""", ) def test_initial_values(self): @@ -1261,12 +1482,13 @@ class ModelFormBasicTests(TestCase): f = ArticleForm( auto_id=False, initial={ - 'headline': 'Your headline here', - 'categories': [str(self.c1.id), str(self.c2.id)] - }) + "headline": "Your headline here", + "categories": [str(self.c1.id), str(self.c2.id)], + }, + ) self.assertHTMLEqual( f.as_ul(), - '''<li>Headline: <input type="text" name="headline" value="Your headline here" maxlength="50" required></li> + """<li>Headline: <input type="text" name="headline" value="Your headline here" maxlength="50" required></li> <li>Slug: <input type="text" name="slug" maxlength="50" required></li> <li>Pub date: <input type="text" name="pub_date" required></li> <li>Writer: <select name="writer" required> @@ -1285,30 +1507,32 @@ class ModelFormBasicTests(TestCase): <option value="1">Draft</option> <option value="2">Pending</option> <option value="3">Live</option> -</select></li>''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk)) +</select></li>""" + % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk), + ) # When the ModelForm is passed an instance, that instance's current values are # inserted as 'initial' data in each Field. f = RoykoForm(auto_id=False, instance=self.w_royko) self.assertHTMLEqual( str(f), - '''<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" required><br> - <span class="helptext">Use both first and last names.</span></td></tr>''' + """<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" required><br> + <span class="helptext">Use both first and last names.</span></td></tr>""", ) art = Article.objects.create( - headline='Test article', - slug='test-article', + headline="Test article", + slug="test-article", pub_date=datetime.date(1988, 1, 4), writer=self.w_royko, - article='Hello.' + article="Hello.", ) art_id_1 = art.id f = ArticleForm(auto_id=False, instance=art) self.assertHTMLEqual( f.as_ul(), - '''<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" required></li> + """<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" required></li> <li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" required></li> <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" required></li> <li>Writer: <select name="writer" required> @@ -1327,21 +1551,26 @@ class ModelFormBasicTests(TestCase): <option value="1">Draft</option> <option value="2">Pending</option> <option value="3">Live</option> -</select></li>''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk)) +</select></li>""" + % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk), + ) - f = ArticleForm({ - 'headline': 'Test headline', - 'slug': 'test-headline', - 'pub_date': '1984-02-06', - 'writer': str(self.w_royko.pk), - 'article': 'Hello.' - }, instance=art) + f = ArticleForm( + { + "headline": "Test headline", + "slug": "test-headline", + "pub_date": "1984-02-06", + "writer": str(self.w_royko.pk), + "article": "Hello.", + }, + instance=art, + ) self.assertEqual(f.errors, {}) self.assertTrue(f.is_valid()) test_art = f.save() self.assertEqual(test_art.id, art_id_1) test_art = Article.objects.get(id=art_id_1) - self.assertEqual(test_art.headline, 'Test headline') + self.assertEqual(test_art.headline, "Test headline") def test_m2m_initial_callable(self): """ @@ -1352,14 +1581,14 @@ class ModelFormBasicTests(TestCase): # Set up a callable initial value def formfield_for_dbfield(db_field, **kwargs): - if db_field.name == 'categories': - kwargs['initial'] = lambda: Category.objects.all().order_by('name')[:2] + if db_field.name == "categories": + kwargs["initial"] = lambda: Category.objects.all().order_by("name")[:2] return db_field.formfield(**kwargs) # Create a ModelForm, instantiate it, and check that the output is as expected ModelForm = modelform_factory( Article, - fields=['headline', 'categories'], + fields=["headline", "categories"], formfield_callback=formfield_for_dbfield, ) form = ModelForm() @@ -1373,19 +1602,22 @@ class ModelFormBasicTests(TestCase): <option value="%d" selected>It's a test</option> <option value="%d">Third test</option> </select></li>""" - % (self.c1.pk, self.c2.pk, self.c3.pk)) + % (self.c1.pk, self.c2.pk, self.c3.pk), + ) def test_basic_creation(self): self.assertEqual(Category.objects.count(), 0) - f = BaseCategoryForm({ - 'name': 'Entertainment', - 'slug': 'entertainment', - 'url': 'entertainment', - }) + f = BaseCategoryForm( + { + "name": "Entertainment", + "slug": "entertainment", + "url": "entertainment", + } + ) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['name'], 'Entertainment') - self.assertEqual(f.cleaned_data['slug'], 'entertainment') - self.assertEqual(f.cleaned_data['url'], 'entertainment') + self.assertEqual(f.cleaned_data["name"], "Entertainment") + self.assertEqual(f.cleaned_data["slug"], "entertainment") + self.assertEqual(f.cleaned_data["url"], "entertainment") c1 = f.save() # Testing whether the same object is returned from the # ORM... not the fastest way... @@ -1398,7 +1630,9 @@ class ModelFormBasicTests(TestCase): # If you call save() with commit=False, then it will return an object that # hasn't yet been saved to the database. In this case, it's up to you to call # save() on the resulting model instance. - f = BaseCategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'}) + f = BaseCategoryForm( + {"name": "Third test", "slug": "third-test", "url": "third"} + ) self.assertTrue(f.is_valid()) c1 = f.save(commit=False) self.assertEqual(c1.name, "Third test") @@ -1408,17 +1642,19 @@ class ModelFormBasicTests(TestCase): def test_save_with_data_errors(self): # If you call save() with invalid data, you'll get a ValueError. - f = BaseCategoryForm({'name': '', 'slug': 'not a slug!', 'url': 'foo'}) - self.assertEqual(f.errors['name'], ['This field is required.']) + f = BaseCategoryForm({"name": "", "slug": "not a slug!", "url": "foo"}) + self.assertEqual(f.errors["name"], ["This field is required."]) self.assertEqual( - f.errors['slug'], - ['Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.'] + f.errors["slug"], + [ + "Enter a valid “slug” consisting of letters, numbers, underscores or hyphens." + ], ) - self.assertEqual(f.cleaned_data, {'url': 'foo'}) + self.assertEqual(f.cleaned_data, {"url": "foo"}) msg = "The Category could not be created because the data didn't validate." with self.assertRaisesMessage(ValueError, msg): f.save() - f = BaseCategoryForm({'name': '', 'slug': '', 'url': 'foo'}) + f = BaseCategoryForm({"name": "", "slug": "", "url": "foo"}) with self.assertRaisesMessage(ValueError, msg): f.save() @@ -1430,7 +1666,7 @@ class ModelFormBasicTests(TestCase): f = ArticleForm(auto_id=False) self.assertHTMLEqual( str(f), - '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" required></td></tr> + """<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" required></td></tr> <tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" required></td></tr> <tr><th>Pub date:</th><td><input type="text" name="pub_date" required></td></tr> <tr><th>Writer:</th><td><select name="writer" required> @@ -1449,18 +1685,24 @@ class ModelFormBasicTests(TestCase): <option value="1">Draft</option> <option value="2">Pending</option> <option value="3">Live</option> -</select></td></tr>''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk)) +</select></td></tr>""" + % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk), + ) # Add some categories and test the many-to-many form output. new_art = Article.objects.create( - article="Hello.", headline="New headline", slug="new-headline", - pub_date=datetime.date(1988, 1, 4), writer=self.w_royko) - new_art.categories.add(Category.objects.get(name='Entertainment')) + article="Hello.", + headline="New headline", + slug="new-headline", + pub_date=datetime.date(1988, 1, 4), + writer=self.w_royko, + ) + new_art.categories.add(Category.objects.get(name="Entertainment")) self.assertSequenceEqual(new_art.categories.all(), [self.c1]) f = ArticleForm(auto_id=False, instance=new_art) self.assertHTMLEqual( f.as_ul(), - '''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" required></li> + """<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" required></li> <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" required></li> <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" required></li> <li>Writer: <select name="writer" required> @@ -1479,7 +1721,9 @@ class ModelFormBasicTests(TestCase): <option value="1">Draft</option> <option value="2">Pending</option> <option value="3">Live</option> -</select></li>''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk)) +</select></li>""" + % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk), + ) def test_subset_fields(self): # You can restrict a form to a subset of the complete list of fields @@ -1491,59 +1735,70 @@ class ModelFormBasicTests(TestCase): class PartialArticleForm(forms.ModelForm): class Meta: model = Article - fields = ('headline', 'pub_date') + fields = ("headline", "pub_date") f = PartialArticleForm(auto_id=False) self.assertHTMLEqual( str(f), - '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" required></td></tr> -<tr><th>Pub date:</th><td><input type="text" name="pub_date" required></td></tr>''') + """<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" required></td></tr> +<tr><th>Pub date:</th><td><input type="text" name="pub_date" required></td></tr>""", + ) class PartialArticleFormWithSlug(forms.ModelForm): class Meta: model = Article - fields = ('headline', 'slug', 'pub_date') + fields = ("headline", "slug", "pub_date") - w_royko = Writer.objects.create(name='Mike Royko') + w_royko = Writer.objects.create(name="Mike Royko") art = Article.objects.create( - article="Hello.", headline="New headline", slug="new-headline", - pub_date=datetime.date(1988, 1, 4), writer=w_royko) - f = PartialArticleFormWithSlug({ - 'headline': 'New headline', - 'slug': 'new-headline', - 'pub_date': '1988-01-04' - }, auto_id=False, instance=art) + article="Hello.", + headline="New headline", + slug="new-headline", + pub_date=datetime.date(1988, 1, 4), + writer=w_royko, + ) + f = PartialArticleFormWithSlug( + { + "headline": "New headline", + "slug": "new-headline", + "pub_date": "1988-01-04", + }, + auto_id=False, + instance=art, + ) self.assertHTMLEqual( f.as_ul(), - '''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" required></li> + """<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" required></li> <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" required></li> -<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" required></li>''' +<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" required></li>""", ) self.assertTrue(f.is_valid()) new_art = f.save() self.assertEqual(new_art.id, art.id) new_art = Article.objects.get(id=art.id) - self.assertEqual(new_art.headline, 'New headline') + self.assertEqual(new_art.headline, "New headline") def test_m2m_editing(self): self.create_basic_data() form_data = { - 'headline': 'New headline', - 'slug': 'new-headline', - 'pub_date': '1988-01-04', - 'writer': str(self.w_royko.pk), - 'article': 'Hello.', - 'categories': [str(self.c1.id), str(self.c2.id)] + "headline": "New headline", + "slug": "new-headline", + "pub_date": "1988-01-04", + "writer": str(self.w_royko.pk), + "article": "Hello.", + "categories": [str(self.c1.id), str(self.c2.id)], } # Create a new article, with categories, via the form. f = ArticleForm(form_data) new_art = f.save() new_art = Article.objects.get(id=new_art.id) art_id_1 = new_art.id - self.assertSequenceEqual(new_art.categories.order_by('name'), [self.c1, self.c2]) + self.assertSequenceEqual( + new_art.categories.order_by("name"), [self.c1, self.c2] + ) # Now, submit form data with no categories. This deletes the existing categories. - form_data['categories'] = [] + form_data["categories"] = [] f = ArticleForm(form_data, instance=new_art) new_art = f.save() self.assertEqual(new_art.id, art_id_1) @@ -1560,7 +1815,7 @@ class ModelFormBasicTests(TestCase): # Create a new article, with categories, via the form, but use commit=False. # The m2m data won't be saved until save_m2m() is invoked on the form. - form_data['categories'] = [str(self.c1.id), str(self.c2.id)] + form_data["categories"] = [str(self.c1.id), str(self.c2.id)] f = ArticleForm(form_data) new_art = f.save(commit=False) @@ -1575,7 +1830,9 @@ class ModelFormBasicTests(TestCase): # Save the m2m data on the form f.save_m2m() - self.assertSequenceEqual(new_art.categories.order_by('name'), [self.c1, self.c2]) + self.assertSequenceEqual( + new_art.categories.order_by("name"), [self.c1, self.c2] + ) def test_custom_form_fields(self): # Here, we define a custom ModelForm. Because it happens to have the same fields as @@ -1588,12 +1845,14 @@ class ModelFormBasicTests(TestCase): class Meta: model = Category - fields = '__all__' + fields = "__all__" - cat = Category.objects.create(name='Third test') - form = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'}, instance=cat) - self.assertEqual(form.save().name, 'Third') - self.assertEqual(Category.objects.get(id=cat.id).name, 'Third') + cat = Category.objects.create(name="Third test") + form = ShortCategory( + {"name": "Third", "slug": "third", "url": "3rd"}, instance=cat + ) + self.assertEqual(form.save().name, "Third") + self.assertEqual(Category.objects.get(id=cat.id).name, "Third") def test_runtime_choicefield_populated(self): self.maxDiff = None @@ -1604,7 +1863,7 @@ class ModelFormBasicTests(TestCase): f = ArticleForm(auto_id=False) self.assertHTMLEqual( f.as_ul(), - '''<li>Headline: <input type="text" name="headline" maxlength="50" required></li> + """<li>Headline: <input type="text" name="headline" maxlength="50" required></li> <li>Slug: <input type="text" name="slug" maxlength="50" required></li> <li>Pub date: <input type="text" name="pub_date" required></li> <li>Writer: <select name="writer" required> @@ -1623,13 +1882,15 @@ class ModelFormBasicTests(TestCase): <option value="1">Draft</option> <option value="2">Pending</option> <option value="3">Live</option> -</select></li>''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk)) +</select></li>""" + % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk), + ) - c4 = Category.objects.create(name='Fourth', url='4th') - w_bernstein = Writer.objects.create(name='Carl Bernstein') + c4 = Category.objects.create(name="Fourth", url="4th") + w_bernstein = Writer.objects.create(name="Carl Bernstein") self.assertHTMLEqual( f.as_ul(), - '''<li>Headline: <input type="text" name="headline" maxlength="50" required></li> + """<li>Headline: <input type="text" name="headline" maxlength="50" required></li> <li>Slug: <input type="text" name="slug" maxlength="50" required></li> <li>Pub date: <input type="text" name="pub_date" required></li> <li>Writer: <select name="writer" required> @@ -1650,64 +1911,79 @@ class ModelFormBasicTests(TestCase): <option value="1">Draft</option> <option value="2">Pending</option> <option value="3">Live</option> -</select></li>''' % (self.w_woodward.pk, w_bernstein.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk, c4.pk)) +</select></li>""" + % ( + self.w_woodward.pk, + w_bernstein.pk, + self.w_royko.pk, + self.c1.pk, + self.c2.pk, + self.c3.pk, + c4.pk, + ), + ) def test_recleaning_model_form_instance(self): """ Re-cleaning an instance that was added via a ModelForm shouldn't raise a pk uniqueness error. """ + class AuthorForm(forms.ModelForm): class Meta: model = Author - fields = '__all__' + fields = "__all__" - form = AuthorForm({'full_name': 'Bob'}) + form = AuthorForm({"full_name": "Bob"}) self.assertTrue(form.is_valid()) obj = form.save() - obj.name = 'Alice' + obj.name = "Alice" obj.full_clean() def test_validate_foreign_key_uses_default_manager(self): class MyForm(forms.ModelForm): class Meta: model = Article - fields = '__all__' + fields = "__all__" # Archived writers are filtered out by the default manager. - w = Writer.objects.create(name='Randy', archived=True) + w = Writer.objects.create(name="Randy", archived=True) data = { - 'headline': 'My Article', - 'slug': 'my-article', - 'pub_date': datetime.date.today(), - 'writer': w.pk, - 'article': 'lorem ipsum', + "headline": "My Article", + "slug": "my-article", + "pub_date": datetime.date.today(), + "writer": w.pk, + "article": "lorem ipsum", } form = MyForm(data) self.assertIs(form.is_valid(), False) self.assertEqual( form.errors, - {'writer': ['Select a valid choice. That choice is not one of the available choices.']}, + { + "writer": [ + "Select a valid choice. That choice is not one of the available choices." + ] + }, ) def test_validate_foreign_key_to_model_with_overridden_manager(self): class MyForm(forms.ModelForm): class Meta: model = Article - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Allow archived authors. - self.fields['writer'].queryset = Writer._base_manager.all() + self.fields["writer"].queryset = Writer._base_manager.all() - w = Writer.objects.create(name='Randy', archived=True) + w = Writer.objects.create(name="Randy", archived=True) data = { - 'headline': 'My Article', - 'slug': 'my-article', - 'pub_date': datetime.date.today(), - 'writer': w.pk, - 'article': 'lorem ipsum', + "headline": "My Article", + "slug": "my-article", + "pub_date": datetime.date.today(), + "writer": w.pk, + "article": "lorem ipsum", } form = MyForm(data) self.assertIs(form.is_valid(), True) @@ -1718,16 +1994,24 @@ class ModelFormBasicTests(TestCase): class ModelMultipleChoiceFieldTests(TestCase): @classmethod def setUpTestData(cls): - cls.c1 = Category.objects.create(name='Entertainment', slug='entertainment', url='entertainment') - cls.c2 = Category.objects.create(name="It's a test", slug='its-test', url='test') - cls.c3 = Category.objects.create(name='Third', slug='third-test', url='third') + cls.c1 = Category.objects.create( + name="Entertainment", slug="entertainment", url="entertainment" + ) + cls.c2 = Category.objects.create( + name="It's a test", slug="its-test", url="test" + ) + cls.c3 = Category.objects.create(name="Third", slug="third-test", url="third") def test_model_multiple_choice_field(self): f = forms.ModelMultipleChoiceField(Category.objects.all()) - self.assertEqual(list(f.choices), [ - (self.c1.pk, 'Entertainment'), - (self.c2.pk, "It's a test"), - (self.c3.pk, 'Third')]) + self.assertEqual( + list(f.choices), + [ + (self.c1.pk, "Entertainment"), + (self.c2.pk, "It's a test"), + (self.c3.pk, "Third"), + ], + ) with self.assertRaises(ValidationError): f.clean(None) with self.assertRaises(ValidationError): @@ -1748,17 +2032,17 @@ class ModelMultipleChoiceFieldTests(TestCase): [self.c1, self.c2], ) with self.assertRaises(ValidationError): - f.clean(['100']) + f.clean(["100"]) with self.assertRaises(ValidationError): - f.clean('hello') + f.clean("hello") with self.assertRaises(ValidationError): - f.clean(['fail']) + f.clean(["fail"]) # Invalid types that require TypeError to be caught (#22808). with self.assertRaises(ValidationError): - f.clean([['fail']]) + f.clean([["fail"]]) with self.assertRaises(ValidationError): - f.clean([{'foo': 'bar'}]) + f.clean([{"foo": "bar"}]) # Add a Category object *after* the ModelMultipleChoiceField has already been # instantiated. This proves clean() checks the database during clean() rather @@ -1766,13 +2050,13 @@ class ModelMultipleChoiceFieldTests(TestCase): # Note, we are using an id of 1006 here since tests that run before # this may create categories with primary keys up to 6. Use # a number that will not conflict. - c6 = Category.objects.create(id=1006, name='Sixth', url='6th') + c6 = Category.objects.create(id=1006, name="Sixth", url="6th") self.assertCountEqual(f.clean([c6.id]), [c6]) # Delete a Category object *after* the ModelMultipleChoiceField has already been # instantiated. This proves clean() checks the database during clean() rather # than caching it at time of instantiation. - Category.objects.get(url='6th').delete() + Category.objects.get(url="6th").delete() with self.assertRaises(ValidationError): f.clean([c6.id]) @@ -1781,17 +2065,18 @@ class ModelMultipleChoiceFieldTests(TestCase): self.assertIsInstance(f.clean([]), EmptyQuerySet) self.assertIsInstance(f.clean(()), EmptyQuerySet) with self.assertRaises(ValidationError): - f.clean(['0']) + f.clean(["0"]) with self.assertRaises(ValidationError): - f.clean([str(self.c3.id), '0']) + f.clean([str(self.c3.id), "0"]) with self.assertRaises(ValidationError): - f.clean([str(self.c1.id), '0']) + f.clean([str(self.c1.id), "0"]) # queryset can be changed after the field is created. - f.queryset = Category.objects.exclude(name='Third') - self.assertEqual(list(f.choices), [ - (self.c1.pk, 'Entertainment'), - (self.c2.pk, "It's a test")]) + f.queryset = Category.objects.exclude(name="Third") + self.assertEqual( + list(f.choices), + [(self.c1.pk, "Entertainment"), (self.c2.pk, "It's a test")], + ) self.assertSequenceEqual(f.clean([self.c2.id]), [self.c2]) with self.assertRaises(ValidationError): f.clean([self.c3.id]) @@ -1800,10 +2085,14 @@ class ModelMultipleChoiceFieldTests(TestCase): f.queryset = Category.objects.all() f.label_from_instance = lambda obj: "multicategory " + str(obj) - self.assertEqual(list(f.choices), [ - (self.c1.pk, 'multicategory Entertainment'), - (self.c2.pk, "multicategory It's a test"), - (self.c3.pk, 'multicategory Third')]) + self.assertEqual( + list(f.choices), + [ + (self.c1.pk, "multicategory Entertainment"), + (self.c2.pk, "multicategory It's a test"), + (self.c3.pk, "multicategory Third"), + ], + ) def test_model_multiple_choice_number_of_queries(self): """ @@ -1826,7 +2115,9 @@ class ModelMultipleChoiceFieldTests(TestCase): def my_validator(value): self._validator_run = True - f = forms.ModelMultipleChoiceField(queryset=Writer.objects.all(), validators=[my_validator]) + f = forms.ModelMultipleChoiceField( + queryset=Writer.objects.all(), validators=[my_validator] + ) f.clean([p.pk for p in Writer.objects.all()[8:9]]) self.assertTrue(self._validator_run) @@ -1834,27 +2125,30 @@ class ModelMultipleChoiceFieldTests(TestCase): """ Test support of show_hidden_initial by ModelMultipleChoiceField. """ + class WriterForm(forms.Form): - persons = forms.ModelMultipleChoiceField(show_hidden_initial=True, queryset=Writer.objects.all()) + persons = forms.ModelMultipleChoiceField( + show_hidden_initial=True, queryset=Writer.objects.all() + ) person1 = Writer.objects.create(name="Person 1") person2 = Writer.objects.create(name="Person 2") form = WriterForm( - initial={'persons': [person1, person2]}, + initial={"persons": [person1, person2]}, data={ - 'initial-persons': [str(person1.pk), str(person2.pk)], - 'persons': [str(person1.pk), str(person2.pk)], + "initial-persons": [str(person1.pk), str(person2.pk)], + "persons": [str(person1.pk), str(person2.pk)], }, ) self.assertTrue(form.is_valid()) self.assertFalse(form.has_changed()) form = WriterForm( - initial={'persons': [person1, person2]}, + initial={"persons": [person1, person2]}, data={ - 'initial-persons': [str(person1.pk), str(person2.pk)], - 'persons': [str(person2.pk)], + "initial-persons": [str(person1.pk), str(person2.pk)], + "persons": [str(person2.pk)], }, ) self.assertTrue(form.is_valid()) @@ -1866,23 +2160,27 @@ class ModelMultipleChoiceFieldTests(TestCase): CheckboxSelectMultiple widget doesn't produce unnecessary db queries when accessing its BoundField's attrs. """ + class ModelMultipleChoiceForm(forms.Form): - categories = forms.ModelMultipleChoiceField(Category.objects.all(), widget=forms.CheckboxSelectMultiple) + categories = forms.ModelMultipleChoiceField( + Category.objects.all(), widget=forms.CheckboxSelectMultiple + ) form = ModelMultipleChoiceForm() - field = form['categories'] # BoundField - template = Template('{{ field.name }}{{ field }}{{ field.help_text }}') + field = form["categories"] # BoundField + template = Template("{{ field.name }}{{ field }}{{ field.help_text }}") with self.assertNumQueries(1): - template.render(Context({'field': field})) + template.render(Context({"field": field})) def test_show_hidden_initial_changed_queries_efficiently(self): class WriterForm(forms.Form): persons = forms.ModelMultipleChoiceField( - show_hidden_initial=True, queryset=Writer.objects.all()) + show_hidden_initial=True, queryset=Writer.objects.all() + ) writers = (Writer.objects.create(name=str(x)) for x in range(0, 50)) writer_pks = tuple(x.pk for x in writers) - form = WriterForm(data={'initial-persons': writer_pks}) + form = WriterForm(data={"initial-persons": writer_pks}) with self.assertNumQueries(1): self.assertTrue(form.has_changed()) @@ -1890,30 +2188,32 @@ class ModelMultipleChoiceFieldTests(TestCase): class PersonForm(forms.Form): persons = forms.ModelMultipleChoiceField(queryset=Person.objects.all()) - person1 = Person.objects.create(name='Person 1') + person1 = Person.objects.create(name="Person 1") form = PersonForm(data={}) - queryset = form.fields['persons'].clean([str(person1.pk)] * 50) + queryset = form.fields["persons"].clean([str(person1.pk)] * 50) sql, params = queryset.query.sql_with_params() self.assertEqual(len(params), 1) def test_to_field_name_with_initial_data(self): class ArticleCategoriesForm(forms.ModelForm): - categories = forms.ModelMultipleChoiceField(Category.objects.all(), to_field_name='slug') + categories = forms.ModelMultipleChoiceField( + Category.objects.all(), to_field_name="slug" + ) class Meta: model = Article - fields = ['categories'] + fields = ["categories"] article = Article.objects.create( - headline='Test article', - slug='test-article', + headline="Test article", + slug="test-article", pub_date=datetime.date(1988, 1, 4), - writer=Writer.objects.create(name='Test writer'), - article='Hello.', + writer=Writer.objects.create(name="Test writer"), + article="Hello.", ) article.categories.add(self.c2, self.c3) form = ArticleCategoriesForm(instance=article) - self.assertCountEqual(form['categories'].value(), [self.c2.slug, self.c3.slug]) + self.assertCountEqual(form["categories"].value(), [self.c2.slug, self.c3.slug]) class ModelOneToOneFieldTests(TestCase): @@ -1921,14 +2221,14 @@ class ModelOneToOneFieldTests(TestCase): class ImprovedArticleForm(forms.ModelForm): class Meta: model = ImprovedArticle - fields = '__all__' + fields = "__all__" class ImprovedArticleWithParentLinkForm(forms.ModelForm): class Meta: model = ImprovedArticleWithParentLink - fields = '__all__' + fields = "__all__" - self.assertEqual(list(ImprovedArticleForm.base_fields), ['article']) + self.assertEqual(list(ImprovedArticleForm.base_fields), ["article"]) self.assertEqual(list(ImprovedArticleWithParentLinkForm.base_fields), []) def test_modelform_subclassed_model(self): @@ -1936,16 +2236,24 @@ class ModelOneToOneFieldTests(TestCase): class Meta: # BetterWriter model is a subclass of Writer with an additional `score` field model = BetterWriter - fields = '__all__' + fields = "__all__" - bw = BetterWriter.objects.create(name='Joe Better', score=10) - self.assertEqual(sorted(model_to_dict(bw)), ['id', 'name', 'score', 'writer_ptr']) + bw = BetterWriter.objects.create(name="Joe Better", score=10) + self.assertEqual( + sorted(model_to_dict(bw)), ["id", "name", "score", "writer_ptr"] + ) self.assertEqual(sorted(model_to_dict(bw, fields=[])), []) - self.assertEqual(sorted(model_to_dict(bw, fields=['id', 'name'])), ['id', 'name']) - self.assertEqual(sorted(model_to_dict(bw, exclude=[])), ['id', 'name', 'score', 'writer_ptr']) - self.assertEqual(sorted(model_to_dict(bw, exclude=['id', 'name'])), ['score', 'writer_ptr']) + self.assertEqual( + sorted(model_to_dict(bw, fields=["id", "name"])), ["id", "name"] + ) + self.assertEqual( + sorted(model_to_dict(bw, exclude=[])), ["id", "name", "score", "writer_ptr"] + ) + self.assertEqual( + sorted(model_to_dict(bw, exclude=["id", "name"])), ["score", "writer_ptr"] + ) - form = BetterWriterForm({'name': 'Some Name', 'score': 12}) + form = BetterWriterForm({"name": "Some Name", "score": 12}) self.assertTrue(form.is_valid()) bw2 = form.save() self.assertEqual(bw2.score, 12) @@ -1955,57 +2263,63 @@ class ModelOneToOneFieldTests(TestCase): class Meta: # WriterProfile has a OneToOneField to Writer model = WriterProfile - fields = '__all__' + fields = "__all__" - self.w_royko = Writer.objects.create(name='Mike Royko') - self.w_woodward = Writer.objects.create(name='Bob Woodward') + self.w_royko = Writer.objects.create(name="Mike Royko") + self.w_woodward = Writer.objects.create(name="Bob Woodward") form = WriterProfileForm() self.assertHTMLEqual( form.as_p(), - '''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer" required> + """<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer" required> <option value="" selected>---------</option> <option value="%s">Bob Woodward</option> <option value="%s">Mike Royko</option> </select></p> -<p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" min="0" required></p>''' % ( - self.w_woodward.pk, self.w_royko.pk, - ) +<p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" min="0" required></p>""" + % ( + self.w_woodward.pk, + self.w_royko.pk, + ), ) data = { - 'writer': str(self.w_woodward.pk), - 'age': '65', + "writer": str(self.w_woodward.pk), + "age": "65", } form = WriterProfileForm(data) instance = form.save() - self.assertEqual(str(instance), 'Bob Woodward is 65') + self.assertEqual(str(instance), "Bob Woodward is 65") form = WriterProfileForm(instance=instance) self.assertHTMLEqual( form.as_p(), - '''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer" required> + """<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer" required> <option value="">---------</option> <option value="%s" selected>Bob Woodward</option> <option value="%s">Mike Royko</option> </select></p> <p><label for="id_age">Age:</label> -<input type="number" name="age" value="65" id="id_age" min="0" required></p>''' % ( - self.w_woodward.pk, self.w_royko.pk, - ) +<input type="number" name="age" value="65" id="id_age" min="0" required></p>""" + % ( + self.w_woodward.pk, + self.w_royko.pk, + ), ) def test_assignment_of_none(self): class AuthorForm(forms.ModelForm): class Meta: model = Author - fields = ['publication', 'full_name'] + fields = ["publication", "full_name"] - publication = Publication.objects.create(title="Pravda", date_published=datetime.date(1991, 8, 22)) - author = Author.objects.create(publication=publication, full_name='John Doe') - form = AuthorForm({'publication': '', 'full_name': 'John Doe'}, instance=author) + publication = Publication.objects.create( + title="Pravda", date_published=datetime.date(1991, 8, 22) + ) + author = Author.objects.create(publication=publication, full_name="John Doe") + form = AuthorForm({"publication": "", "full_name": "John Doe"}, instance=author) self.assertTrue(form.is_valid()) - self.assertIsNone(form.cleaned_data['publication']) + self.assertIsNone(form.cleaned_data["publication"]) author = form.save() # author object returned from form still retains original publication object # that's why we need to retrieve it from database again @@ -2016,11 +2330,13 @@ class ModelOneToOneFieldTests(TestCase): class AuthorForm(forms.ModelForm): class Meta: model = Author1 - fields = ['publication', 'full_name'] + fields = ["publication", "full_name"] - publication = Publication.objects.create(title="Pravda", date_published=datetime.date(1991, 8, 22)) - author = Author1.objects.create(publication=publication, full_name='John Doe') - form = AuthorForm({'publication': '', 'full_name': 'John Doe'}, instance=author) + publication = Publication.objects.create( + title="Pravda", date_published=datetime.date(1991, 8, 22) + ) + author = Author1.objects.create(publication=publication, full_name="John Doe") + form = AuthorForm({"publication": "", "full_name": "John Doe"}, instance=author) self.assertFalse(form.is_valid()) @@ -2033,7 +2349,7 @@ class FileAndImageFieldTests(TestCase): """ f = forms.FileField(required=False) self.assertIs(f.clean(False), False) - self.assertIs(f.clean(False, 'initial'), False) + self.assertIs(f.clean(False, "initial"), False) def test_clean_false_required(self): """ @@ -2042,7 +2358,7 @@ class FileAndImageFieldTests(TestCase): otherwise the validation catches the lack of a required value. """ f = forms.FileField(required=True) - self.assertEqual(f.clean(False, 'initial'), 'initial') + self.assertEqual(f.clean(False, "initial"), "initial") with self.assertRaises(ValidationError): f.clean(False) @@ -2051,21 +2367,24 @@ class FileAndImageFieldTests(TestCase): Integration happy-path test that a model FileField can actually be set and cleared via a ModelForm. """ + class DocumentForm(forms.ModelForm): class Meta: model = Document - fields = '__all__' + fields = "__all__" form = DocumentForm() self.assertIn('name="myfile"', str(form)) - self.assertNotIn('myfile-clear', str(form)) - form = DocumentForm(files={'myfile': SimpleUploadedFile('something.txt', b'content')}) + self.assertNotIn("myfile-clear", str(form)) + form = DocumentForm( + files={"myfile": SimpleUploadedFile("something.txt", b"content")} + ) self.assertTrue(form.is_valid()) doc = form.save(commit=False) - self.assertEqual(doc.myfile.name, 'something.txt') + self.assertEqual(doc.myfile.name, "something.txt") form = DocumentForm(instance=doc) - self.assertIn('myfile-clear', str(form)) - form = DocumentForm(instance=doc, data={'myfile-clear': 'true'}) + self.assertIn("myfile-clear", str(form)) + form = DocumentForm(instance=doc, data={"myfile-clear": "true"}) doc = form.save(commit=False) self.assertFalse(doc.myfile) @@ -2075,94 +2394,98 @@ class FileAndImageFieldTests(TestCase): they get a validation error, and the bound redisplay of the form still includes the current file and the clear checkbox. """ + class DocumentForm(forms.ModelForm): class Meta: model = Document - fields = '__all__' + fields = "__all__" - form = DocumentForm(files={'myfile': SimpleUploadedFile('something.txt', b'content')}) + form = DocumentForm( + files={"myfile": SimpleUploadedFile("something.txt", b"content")} + ) self.assertTrue(form.is_valid()) doc = form.save(commit=False) form = DocumentForm( instance=doc, - files={'myfile': SimpleUploadedFile('something.txt', b'content')}, - data={'myfile-clear': 'true'}, + files={"myfile": SimpleUploadedFile("something.txt", b"content")}, + data={"myfile-clear": "true"}, ) self.assertTrue(not form.is_valid()) - self.assertEqual(form.errors['myfile'], - ['Please either submit a file or check the clear checkbox, not both.']) + self.assertEqual( + form.errors["myfile"], + ["Please either submit a file or check the clear checkbox, not both."], + ) rendered = str(form) - self.assertIn('something.txt', rendered) - self.assertIn('myfile-clear', rendered) + self.assertIn("something.txt", rendered) + self.assertIn("myfile-clear", rendered) def test_render_empty_file_field(self): class DocumentForm(forms.ModelForm): class Meta: model = Document - fields = '__all__' + fields = "__all__" doc = Document.objects.create() form = DocumentForm(instance=doc) self.assertHTMLEqual( - str(form['myfile']), - '<input id="id_myfile" name="myfile" type="file">' + str(form["myfile"]), '<input id="id_myfile" name="myfile" type="file">' ) def test_file_field_data(self): # Test conditions when files is either not given or empty. - f = TextFileForm(data={'description': 'Assistance'}) + f = TextFileForm(data={"description": "Assistance"}) self.assertFalse(f.is_valid()) - f = TextFileForm(data={'description': 'Assistance'}, files={}) + f = TextFileForm(data={"description": "Assistance"}, files={}) self.assertFalse(f.is_valid()) # Upload a file and ensure it all works as expected. f = TextFileForm( - data={'description': 'Assistance'}, - files={'file': SimpleUploadedFile('test1.txt', b'hello world')}, + data={"description": "Assistance"}, + files={"file": SimpleUploadedFile("test1.txt", b"hello world")}, ) self.assertTrue(f.is_valid()) - self.assertEqual(type(f.cleaned_data['file']), SimpleUploadedFile) + self.assertEqual(type(f.cleaned_data["file"]), SimpleUploadedFile) instance = f.save() - self.assertEqual(instance.file.name, 'tests/test1.txt') + self.assertEqual(instance.file.name, "tests/test1.txt") instance.file.delete() # If the previous file has been deleted, the file name can be reused f = TextFileForm( - data={'description': 'Assistance'}, - files={'file': SimpleUploadedFile('test1.txt', b'hello world')}, + data={"description": "Assistance"}, + files={"file": SimpleUploadedFile("test1.txt", b"hello world")}, ) self.assertTrue(f.is_valid()) - self.assertEqual(type(f.cleaned_data['file']), SimpleUploadedFile) + self.assertEqual(type(f.cleaned_data["file"]), SimpleUploadedFile) instance = f.save() - self.assertEqual(instance.file.name, 'tests/test1.txt') + self.assertEqual(instance.file.name, "tests/test1.txt") # Check if the max_length attribute has been inherited from the model. f = TextFileForm( - data={'description': 'Assistance'}, - files={'file': SimpleUploadedFile('test-maxlength.txt', b'hello world')}, + data={"description": "Assistance"}, + files={"file": SimpleUploadedFile("test-maxlength.txt", b"hello world")}, ) self.assertFalse(f.is_valid()) # Edit an instance that already has the file defined in the model. This will not # save the file again, but leave it exactly as it is. - f = TextFileForm({'description': 'Assistance'}, instance=instance) + f = TextFileForm({"description": "Assistance"}, instance=instance) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['file'].name, 'tests/test1.txt') + self.assertEqual(f.cleaned_data["file"].name, "tests/test1.txt") instance = f.save() - self.assertEqual(instance.file.name, 'tests/test1.txt') + self.assertEqual(instance.file.name, "tests/test1.txt") # Delete the current file since this is not done by Django. instance.file.delete() # Override the file by uploading a new one. f = TextFileForm( - data={'description': 'Assistance'}, - files={'file': SimpleUploadedFile('test2.txt', b'hello world')}, + data={"description": "Assistance"}, + files={"file": SimpleUploadedFile("test2.txt", b"hello world")}, instance=instance, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.file.name, 'tests/test2.txt') + self.assertEqual(instance.file.name, "tests/test2.txt") # Delete the current file since this is not done by Django. instance.file.delete() @@ -2170,28 +2493,28 @@ class FileAndImageFieldTests(TestCase): def test_filefield_required_false(self): # Test the non-required FileField - f = TextFileForm(data={'description': 'Assistance'}) - f.fields['file'].required = False + f = TextFileForm(data={"description": "Assistance"}) + f.fields["file"].required = False self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.file.name, '') + self.assertEqual(instance.file.name, "") f = TextFileForm( - data={'description': 'Assistance'}, - files={'file': SimpleUploadedFile('test3.txt', b'hello world')}, + data={"description": "Assistance"}, + files={"file": SimpleUploadedFile("test3.txt", b"hello world")}, instance=instance, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.file.name, 'tests/test3.txt') + self.assertEqual(instance.file.name, "tests/test3.txt") # Instance can be edited w/out re-uploading the file and existing file should be preserved. - f = TextFileForm({'description': 'New Description'}, instance=instance) - f.fields['file'].required = False + f = TextFileForm({"description": "New Description"}, instance=instance) + f.fields["file"].required = False self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.description, 'New Description') - self.assertEqual(instance.file.name, 'tests/test3.txt') + self.assertEqual(instance.description, "New Description") + self.assertEqual(instance.file.name, "tests/test3.txt") # Delete the current file since this is not done by Django. instance.file.delete() @@ -2201,14 +2524,15 @@ class FileAndImageFieldTests(TestCase): """ Regression for #11149: save_form_data should be called only once """ + class CFFForm(forms.ModelForm): class Meta: model = CustomFF - fields = '__all__' + fields = "__all__" # It's enough that the form saves without error -- the custom save routine will # generate an AssertionError if it is called more than once during save. - form = CFFForm(data={'f': None}) + form = CFFForm(data={"f": None}) form.save() def test_file_field_multiple_save(self): @@ -2216,19 +2540,20 @@ class FileAndImageFieldTests(TestCase): Simulate a file upload and check how many times Model.save() gets called. Test for bug #639. """ + class PhotoForm(forms.ModelForm): class Meta: model = Photo - fields = '__all__' + fields = "__all__" # Grab an image for testing. - filename = os.path.join(os.path.dirname(__file__), 'test.png') + filename = os.path.join(os.path.dirname(__file__), "test.png") with open(filename, "rb") as fp: img = fp.read() # Fake a POST QueryDict and FILES MultiValueDict. - data = {'title': 'Testing'} - files = {"image": SimpleUploadedFile('test.png', img, 'image/png')} + data = {"title": "Testing"} + files = {"image": SimpleUploadedFile("test.png", img, "image/png")} form = PhotoForm(data=data, files=files) p = form.save() @@ -2243,13 +2568,16 @@ class FileAndImageFieldTests(TestCase): def test_file_path_field_blank(self): """FilePathField(blank=True) includes the empty option.""" + class FPForm(forms.ModelForm): class Meta: model = FilePathModel - fields = '__all__' + fields = "__all__" form = FPForm() - self.assertEqual([name for _, name in form['path'].field.choices], ['---------', 'models.py']) + self.assertEqual( + [name for _, name in form["path"].field.choices], ["---------", "models.py"] + ) @skipUnless(test_images, "Pillow not installed") def test_image_field(self): @@ -2257,19 +2585,19 @@ class FileAndImageFieldTests(TestCase): # it comes to validation. This specifically tests that #6302 is fixed for # both file fields and image fields. - with open(os.path.join(os.path.dirname(__file__), 'test.png'), 'rb') as fp: + with open(os.path.join(os.path.dirname(__file__), "test.png"), "rb") as fp: image_data = fp.read() - with open(os.path.join(os.path.dirname(__file__), 'test2.png'), 'rb') as fp: + with open(os.path.join(os.path.dirname(__file__), "test2.png"), "rb") as fp: image_data2 = fp.read() f = ImageFileForm( - data={'description': 'An image'}, - files={'image': SimpleUploadedFile('test.png', image_data)}, + data={"description": "An image"}, + files={"image": SimpleUploadedFile("test.png", image_data)}, ) self.assertTrue(f.is_valid()) - self.assertEqual(type(f.cleaned_data['image']), SimpleUploadedFile) + self.assertEqual(type(f.cleaned_data["image"]), SimpleUploadedFile) instance = f.save() - self.assertEqual(instance.image.name, 'tests/test.png') + self.assertEqual(instance.image.name, "tests/test.png") self.assertEqual(instance.width, 16) self.assertEqual(instance.height, 16) @@ -2277,24 +2605,24 @@ class FileAndImageFieldTests(TestCase): # because the dimension fields are not null=True. instance.image.delete(save=False) f = ImageFileForm( - data={'description': 'An image'}, - files={'image': SimpleUploadedFile('test.png', image_data)}, + data={"description": "An image"}, + files={"image": SimpleUploadedFile("test.png", image_data)}, ) self.assertTrue(f.is_valid()) - self.assertEqual(type(f.cleaned_data['image']), SimpleUploadedFile) + self.assertEqual(type(f.cleaned_data["image"]), SimpleUploadedFile) instance = f.save() - self.assertEqual(instance.image.name, 'tests/test.png') + self.assertEqual(instance.image.name, "tests/test.png") self.assertEqual(instance.width, 16) self.assertEqual(instance.height, 16) # Edit an instance that already has the (required) image defined in the model. This will not # save the image again, but leave it exactly as it is. - f = ImageFileForm(data={'description': 'Look, it changed'}, instance=instance) + f = ImageFileForm(data={"description": "Look, it changed"}, instance=instance) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['image'].name, 'tests/test.png') + self.assertEqual(f.cleaned_data["image"].name, "tests/test.png") instance = f.save() - self.assertEqual(instance.image.name, 'tests/test.png') + self.assertEqual(instance.image.name, "tests/test.png") self.assertEqual(instance.height, 16) self.assertEqual(instance.width, 16) @@ -2304,13 +2632,13 @@ class FileAndImageFieldTests(TestCase): # Override the file by uploading a new one. f = ImageFileForm( - data={'description': 'Changed it'}, - files={'image': SimpleUploadedFile('test2.png', image_data2)}, + data={"description": "Changed it"}, + files={"image": SimpleUploadedFile("test2.png", image_data2)}, instance=instance, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.image.name, 'tests/test2.png') + self.assertEqual(instance.image.name, "tests/test2.png") self.assertEqual(instance.height, 32) self.assertEqual(instance.width, 48) @@ -2320,12 +2648,12 @@ class FileAndImageFieldTests(TestCase): instance.delete() f = ImageFileForm( - data={'description': 'Changed it'}, - files={'image': SimpleUploadedFile('test2.png', image_data2)}, + data={"description": "Changed it"}, + files={"image": SimpleUploadedFile("test2.png", image_data2)}, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.image.name, 'tests/test2.png') + self.assertEqual(instance.image.name, "tests/test2.png") self.assertEqual(instance.height, 32) self.assertEqual(instance.width, 48) @@ -2338,11 +2666,11 @@ class FileAndImageFieldTests(TestCase): # Note: In Oracle, we expect a null ImageField to return '' instead of # None. if connection.features.interprets_empty_strings_as_nulls: - expected_null_imagefield_repr = '' + expected_null_imagefield_repr = "" else: expected_null_imagefield_repr = None - f = OptionalImageFileForm(data={'description': 'Test'}) + f = OptionalImageFileForm(data={"description": "Test"}) self.assertTrue(f.is_valid()) instance = f.save() self.assertEqual(instance.image.name, expected_null_imagefield_repr) @@ -2350,23 +2678,23 @@ class FileAndImageFieldTests(TestCase): self.assertIsNone(instance.height) f = OptionalImageFileForm( - data={'description': 'And a final one'}, - files={'image': SimpleUploadedFile('test3.png', image_data)}, + data={"description": "And a final one"}, + files={"image": SimpleUploadedFile("test3.png", image_data)}, instance=instance, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.image.name, 'tests/test3.png') + self.assertEqual(instance.image.name, "tests/test3.png") self.assertEqual(instance.width, 16) self.assertEqual(instance.height, 16) # Editing the instance without re-uploading the image should not affect # the image or its width/height properties. - f = OptionalImageFileForm({'description': 'New Description'}, instance=instance) + f = OptionalImageFileForm({"description": "New Description"}, instance=instance) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.description, 'New Description') - self.assertEqual(instance.image.name, 'tests/test3.png') + self.assertEqual(instance.description, "New Description") + self.assertEqual(instance.image.name, "tests/test3.png") self.assertEqual(instance.width, 16) self.assertEqual(instance.height, 16) @@ -2375,75 +2703,91 @@ class FileAndImageFieldTests(TestCase): instance.delete() f = OptionalImageFileForm( - data={'description': 'And a final one'}, - files={'image': SimpleUploadedFile('test4.png', image_data2)} + data={"description": "And a final one"}, + files={"image": SimpleUploadedFile("test4.png", image_data2)}, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.image.name, 'tests/test4.png') + self.assertEqual(instance.image.name, "tests/test4.png") self.assertEqual(instance.width, 48) self.assertEqual(instance.height, 32) instance.delete() # Test callable upload_to behavior that's dependent on the value of another field in the model f = ImageFileForm( - data={'description': 'And a final one', 'path': 'foo'}, - files={'image': SimpleUploadedFile('test4.png', image_data)}, + data={"description": "And a final one", "path": "foo"}, + files={"image": SimpleUploadedFile("test4.png", image_data)}, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.image.name, 'foo/test4.png') + self.assertEqual(instance.image.name, "foo/test4.png") instance.delete() # Editing an instance that has an image without an extension shouldn't # fail validation. First create: f = NoExtensionImageFileForm( - data={'description': 'An image'}, - files={'image': SimpleUploadedFile('test.png', image_data)}, + data={"description": "An image"}, + files={"image": SimpleUploadedFile("test.png", image_data)}, ) self.assertTrue(f.is_valid()) instance = f.save() - self.assertEqual(instance.image.name, 'tests/no_extension') + self.assertEqual(instance.image.name, "tests/no_extension") # Then edit: - f = NoExtensionImageFileForm(data={'description': 'Edited image'}, instance=instance) + f = NoExtensionImageFileForm( + data={"description": "Edited image"}, instance=instance + ) self.assertTrue(f.is_valid()) class ModelOtherFieldTests(SimpleTestCase): def test_big_integer_field(self): - bif = BigIntForm({'biggie': '-9223372036854775808'}) + bif = BigIntForm({"biggie": "-9223372036854775808"}) self.assertTrue(bif.is_valid()) - bif = BigIntForm({'biggie': '-9223372036854775809'}) + bif = BigIntForm({"biggie": "-9223372036854775809"}) self.assertFalse(bif.is_valid()) self.assertEqual( bif.errors, - {'biggie': ['Ensure this value is greater than or equal to -9223372036854775808.']} + { + "biggie": [ + "Ensure this value is greater than or equal to -9223372036854775808." + ] + }, ) - bif = BigIntForm({'biggie': '9223372036854775807'}) + bif = BigIntForm({"biggie": "9223372036854775807"}) self.assertTrue(bif.is_valid()) - bif = BigIntForm({'biggie': '9223372036854775808'}) + bif = BigIntForm({"biggie": "9223372036854775808"}) self.assertFalse(bif.is_valid()) - self.assertEqual(bif.errors, {'biggie': ['Ensure this value is less than or equal to 9223372036854775807.']}) + self.assertEqual( + bif.errors, + { + "biggie": [ + "Ensure this value is less than or equal to 9223372036854775807." + ] + }, + ) def test_url_on_modelform(self): "Check basic URL field validation on model forms" + class HomepageForm(forms.ModelForm): class Meta: model = Homepage - fields = '__all__' + fields = "__all__" - self.assertFalse(HomepageForm({'url': 'foo'}).is_valid()) - self.assertFalse(HomepageForm({'url': 'http://'}).is_valid()) - self.assertFalse(HomepageForm({'url': 'http://example'}).is_valid()) - self.assertFalse(HomepageForm({'url': 'http://example.'}).is_valid()) - self.assertFalse(HomepageForm({'url': 'http://com.'}).is_valid()) + self.assertFalse(HomepageForm({"url": "foo"}).is_valid()) + self.assertFalse(HomepageForm({"url": "http://"}).is_valid()) + self.assertFalse(HomepageForm({"url": "http://example"}).is_valid()) + self.assertFalse(HomepageForm({"url": "http://example."}).is_valid()) + self.assertFalse(HomepageForm({"url": "http://com."}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://localhost'}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://example.com'}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://www.example.com'}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://www.example.com:8000'}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://www.example.com/test'}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://www.example.com:8000/test'}).is_valid()) - self.assertTrue(HomepageForm({'url': 'http://example.com/foo/bar'}).is_valid()) + self.assertTrue(HomepageForm({"url": "http://localhost"}).is_valid()) + self.assertTrue(HomepageForm({"url": "http://example.com"}).is_valid()) + self.assertTrue(HomepageForm({"url": "http://www.example.com"}).is_valid()) + self.assertTrue(HomepageForm({"url": "http://www.example.com:8000"}).is_valid()) + self.assertTrue(HomepageForm({"url": "http://www.example.com/test"}).is_valid()) + self.assertTrue( + HomepageForm({"url": "http://www.example.com:8000/test"}).is_valid() + ) + self.assertTrue(HomepageForm({"url": "http://example.com/foo/bar"}).is_valid()) def test_modelform_non_editable_field(self): """ @@ -2451,31 +2795,33 @@ class ModelOtherFieldTests(SimpleTestCase): error message should be explicit. """ # 'created', non-editable, is excluded by default - self.assertNotIn('created', ArticleForm().fields) + self.assertNotIn("created", ArticleForm().fields) msg = "'created' cannot be specified for Article model form as it is a non-editable field" with self.assertRaisesMessage(FieldError, msg): + class InvalidArticleForm(forms.ModelForm): class Meta: model = Article - fields = ('headline', 'created') + fields = ("headline", "created") def test_http_prefixing(self): """ If the http:// prefix is omitted on form input, the field adds it again. (Refs #13613) """ + class HomepageForm(forms.ModelForm): class Meta: model = Homepage - fields = '__all__' + fields = "__all__" - form = HomepageForm({'url': 'example.com'}) + form = HomepageForm({"url": "example.com"}) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['url'], 'http://example.com') + self.assertEqual(form.cleaned_data["url"], "http://example.com") - form = HomepageForm({'url': 'example.com/test'}) + form = HomepageForm({"url": "example.com/test"}) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['url'], 'http://example.com/test') + self.assertEqual(form.cleaned_data["url"], "http://example.com/test") class OtherModelFormTests(TestCase): @@ -2486,25 +2832,25 @@ class OtherModelFormTests(TestCase): self.assertHTMLEqual( str(f.media), '<link href="/some/form/css" media="all" rel="stylesheet">' - '<script src="/some/form/javascript"></script>' + '<script src="/some/form/javascript"></script>', ) def test_choices_type(self): # Choices on CharField and IntegerField f = ArticleForm() with self.assertRaises(ValidationError): - f.fields['status'].clean('42') + f.fields["status"].clean("42") f = ArticleStatusForm() with self.assertRaises(ValidationError): - f.fields['status'].clean('z') + f.fields["status"].clean("z") def test_prefetch_related_queryset(self): """ ModelChoiceField should respect a prefetch_related() on its queryset. """ - blue = Colour.objects.create(name='blue') - red = Colour.objects.create(name='red') + blue = Colour.objects.create(name="blue") + red = Colour.objects.create(name="red") multicolor_item = ColourfulItem.objects.create() multicolor_item.colours.add(blue, red) red_item = ColourfulItem.objects.create() @@ -2512,83 +2858,92 @@ class OtherModelFormTests(TestCase): class ColorModelChoiceField(forms.ModelChoiceField): def label_from_instance(self, obj): - return ', '.join(c.name for c in obj.colours.all()) + return ", ".join(c.name for c in obj.colours.all()) - field = ColorModelChoiceField(ColourfulItem.objects.prefetch_related('colours')) + field = ColorModelChoiceField(ColourfulItem.objects.prefetch_related("colours")) with self.assertNumQueries(3): # would be 4 if prefetch is ignored - self.assertEqual(tuple(field.choices), ( - ('', '---------'), - (multicolor_item.pk, 'blue, red'), - (red_item.pk, 'red'), - )) + self.assertEqual( + tuple(field.choices), + ( + ("", "---------"), + (multicolor_item.pk, "blue, red"), + (red_item.pk, "red"), + ), + ) def test_foreignkeys_which_use_to_field(self): - apple = Inventory.objects.create(barcode=86, name='Apple') - pear = Inventory.objects.create(barcode=22, name='Pear') - core = Inventory.objects.create(barcode=87, name='Core', parent=apple) + apple = Inventory.objects.create(barcode=86, name="Apple") + pear = Inventory.objects.create(barcode=22, name="Pear") + core = Inventory.objects.create(barcode=87, name="Core", parent=apple) - field = forms.ModelChoiceField(Inventory.objects.all(), to_field_name='barcode') - self.assertEqual(tuple(field.choices), ( - ('', '---------'), - (86, 'Apple'), - (87, 'Core'), - (22, 'Pear'))) + field = forms.ModelChoiceField(Inventory.objects.all(), to_field_name="barcode") + self.assertEqual( + tuple(field.choices), + (("", "---------"), (86, "Apple"), (87, "Core"), (22, "Pear")), + ) form = InventoryForm(instance=core) - self.assertHTMLEqual(str(form['parent']), '''<select name="parent" id="id_parent"> + self.assertHTMLEqual( + str(form["parent"]), + """<select name="parent" id="id_parent"> <option value="">---------</option> <option value="86" selected>Apple</option> <option value="87">Core</option> <option value="22">Pear</option> -</select>''') +</select>""", + ) data = model_to_dict(core) - data['parent'] = '22' + data["parent"] = "22" form = InventoryForm(data=data, instance=core) core = form.save() - self.assertEqual(core.parent.name, 'Pear') + self.assertEqual(core.parent.name, "Pear") class CategoryForm(forms.ModelForm): description = forms.CharField() class Meta: model = Category - fields = ['description', 'url'] + fields = ["description", "url"] - self.assertEqual(list(CategoryForm.base_fields), ['description', 'url']) + self.assertEqual(list(CategoryForm.base_fields), ["description", "url"]) self.assertHTMLEqual( str(CategoryForm()), - '''<tr><th><label for="id_description">Description:</label></th> + """<tr><th><label for="id_description">Description:</label></th> <td><input type="text" name="description" id="id_description" required></td></tr> <tr><th><label for="id_url">The URL:</label></th> -<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>''' +<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>""", ) # to_field_name should also work on ModelMultipleChoiceField ################## - field = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode') - self.assertEqual(tuple(field.choices), ((86, 'Apple'), (87, 'Core'), (22, 'Pear'))) + field = forms.ModelMultipleChoiceField( + Inventory.objects.all(), to_field_name="barcode" + ) + self.assertEqual( + tuple(field.choices), ((86, "Apple"), (87, "Core"), (22, "Pear")) + ) self.assertSequenceEqual(field.clean([86]), [apple]) - form = SelectInventoryForm({'items': [87, 22]}) + form = SelectInventoryForm({"items": [87, 22]}) self.assertTrue(form.is_valid()) self.assertEqual(len(form.cleaned_data), 1) - self.assertSequenceEqual(form.cleaned_data['items'], [core, pear]) + self.assertSequenceEqual(form.cleaned_data["items"], [core, pear]) def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self): - self.assertEqual(list(CustomFieldForExclusionForm.base_fields), ['name']) + self.assertEqual(list(CustomFieldForExclusionForm.base_fields), ["name"]) self.assertHTMLEqual( str(CustomFieldForExclusionForm()), - '''<tr><th><label for="id_name">Name:</label></th> -<td><input id="id_name" type="text" name="name" maxlength="10" required></td></tr>''' + """<tr><th><label for="id_name">Name:</label></th> +<td><input id="id_name" type="text" name="name" maxlength="10" required></td></tr>""", ) def test_iterable_model_m2m(self): class ColourfulItemForm(forms.ModelForm): class Meta: model = ColourfulItem - fields = '__all__' + fields = "__all__" - colour = Colour.objects.create(name='Blue') + colour = Colour.objects.create(name="Blue") form = ColourfulItemForm() self.maxDiff = 1024 self.assertHTMLEqual( @@ -2598,13 +2953,14 @@ class OtherModelFormTests(TestCase): <select multiple name="colours" id="id_colours" required> <option value="%(blue_pk)s">Blue</option> </select></p>""" - % {'blue_pk': colour.pk}) + % {"blue_pk": colour.pk}, + ) def test_callable_field_default(self): class PublicationDefaultsForm(forms.ModelForm): class Meta: model = PublicationDefaults - fields = ('title', 'date_published', 'mode', 'category') + fields = ("title", "date_published", "mode", "category") self.maxDiff = 2000 form = PublicationDefaultsForm() @@ -2626,16 +2982,18 @@ class OtherModelFormTests(TestCase): <option value="2">Comics</option> <option value="3" selected>Novel</option></select> <input id="initial-id_category" name="initial-category" type="hidden" value="3"> - """.format(today_str) + """.format( + today_str + ), ) empty_data = { - 'title': '', - 'date_published': today_str, - 'initial-date_published': today_str, - 'mode': 'di', - 'initial-mode': 'di', - 'category': '3', - 'initial-category': '3', + "title": "", + "date_published": today_str, + "initial-date_published": today_str, + "mode": "di", + "initial-mode": "di", + "category": "3", + "initial-category": "3", } bound_form = PublicationDefaultsForm(empty_data) self.assertFalse(bound_form.has_changed()) @@ -2643,36 +3001,36 @@ class OtherModelFormTests(TestCase): class ModelFormCustomErrorTests(SimpleTestCase): def test_custom_error_messages(self): - data = {'name1': '@#$!!**@#$', 'name2': '@#$!!**@#$'} + data = {"name1": "@#$!!**@#$", "name2": "@#$!!**@#$"} errors = CustomErrorMessageForm(data).errors self.assertHTMLEqual( - str(errors['name1']), - '<ul class="errorlist"><li>Form custom error message.</li></ul>' + str(errors["name1"]), + '<ul class="errorlist"><li>Form custom error message.</li></ul>', ) self.assertHTMLEqual( - str(errors['name2']), - '<ul class="errorlist"><li>Model custom error message.</li></ul>' + str(errors["name2"]), + '<ul class="errorlist"><li>Model custom error message.</li></ul>', ) def test_model_clean_error_messages(self): - data = {'name1': 'FORBIDDEN_VALUE', 'name2': 'ABC'} + data = {"name1": "FORBIDDEN_VALUE", "name2": "ABC"} form = CustomErrorMessageForm(data) self.assertFalse(form.is_valid()) self.assertHTMLEqual( - str(form.errors['name1']), - '<ul class="errorlist"><li>Model.clean() error messages.</li></ul>' + str(form.errors["name1"]), + '<ul class="errorlist"><li>Model.clean() error messages.</li></ul>', ) - data = {'name1': 'FORBIDDEN_VALUE2', 'name2': 'ABC'} + data = {"name1": "FORBIDDEN_VALUE2", "name2": "ABC"} form = CustomErrorMessageForm(data) self.assertFalse(form.is_valid()) self.assertHTMLEqual( - str(form.errors['name1']), - '<ul class="errorlist"><li>Model.clean() error messages (simpler syntax).</li></ul>' + str(form.errors["name1"]), + '<ul class="errorlist"><li>Model.clean() error messages (simpler syntax).</li></ul>', ) - data = {'name1': 'GLOBAL_ERROR', 'name2': 'ABC'} + data = {"name1": "GLOBAL_ERROR", "name2": "ABC"} form = CustomErrorMessageForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors['__all__'], ['Global error message.']) + self.assertEqual(form.errors["__all__"], ["Global error message."]) class CustomCleanTests(TestCase): @@ -2681,17 +3039,18 @@ class CustomCleanTests(TestCase): Regression for #12596: Calling super from ModelForm.clean() should be optional. """ + class TripleFormWithCleanOverride(forms.ModelForm): class Meta: model = Triple - fields = '__all__' + fields = "__all__" def clean(self): - if not self.cleaned_data['left'] == self.cleaned_data['right']: - raise ValidationError('Left and right should be equal') + if not self.cleaned_data["left"] == self.cleaned_data["right"]: + raise ValidationError("Left and right should be equal") return self.cleaned_data - form = TripleFormWithCleanOverride({'left': 1, 'middle': 2, 'right': 1}) + form = TripleFormWithCleanOverride({"left": 1, "middle": 2, "right": 1}) self.assertTrue(form.is_valid()) # form.instance.left will be None if the instance was not constructed # by form.full_clean(). @@ -2702,19 +3061,20 @@ class CustomCleanTests(TestCase): Regression test for #12960. Make sure the cleaned_data returned from ModelForm.clean() is applied to the model instance. """ + class CategoryForm(forms.ModelForm): class Meta: model = Category - fields = '__all__' + fields = "__all__" def clean(self): - self.cleaned_data['name'] = self.cleaned_data['name'].upper() + self.cleaned_data["name"] = self.cleaned_data["name"].upper() return self.cleaned_data - data = {'name': 'Test', 'slug': 'test', 'url': '/test'} + data = {"name": "Test", "slug": "test", "url": "/test"} form = CategoryForm(data) category = form.save() - self.assertEqual(category.name, 'TEST') + self.assertEqual(category.name, "TEST") class ModelFormInheritanceTests(SimpleTestCase): @@ -2725,15 +3085,15 @@ class ModelFormInheritanceTests(SimpleTestCase): class ModelForm(forms.ModelForm, Form): class Meta: model = Writer - fields = '__all__' + fields = "__all__" - self.assertEqual(list(ModelForm().fields), ['name', 'age']) + self.assertEqual(list(ModelForm().fields), ["name", "age"]) def test_field_removal(self): class ModelForm(forms.ModelForm): class Meta: model = Writer - fields = '__all__' + fields = "__all__" class Mixin: age = None @@ -2744,39 +3104,51 @@ class ModelFormInheritanceTests(SimpleTestCase): class Form2(forms.Form): foo = forms.IntegerField() - self.assertEqual(list(ModelForm().fields), ['name']) - self.assertEqual(list(type('NewForm', (Mixin, Form), {})().fields), []) - self.assertEqual(list(type('NewForm', (Form2, Mixin, Form), {})().fields), ['foo']) - self.assertEqual(list(type('NewForm', (Mixin, ModelForm, Form), {})().fields), ['name']) - self.assertEqual(list(type('NewForm', (ModelForm, Mixin, Form), {})().fields), ['name']) - self.assertEqual(list(type('NewForm', (ModelForm, Form, Mixin), {})().fields), ['name', 'age']) - self.assertEqual(list(type('NewForm', (ModelForm, Form), {'age': None})().fields), ['name']) + self.assertEqual(list(ModelForm().fields), ["name"]) + self.assertEqual(list(type("NewForm", (Mixin, Form), {})().fields), []) + self.assertEqual( + list(type("NewForm", (Form2, Mixin, Form), {})().fields), ["foo"] + ) + self.assertEqual( + list(type("NewForm", (Mixin, ModelForm, Form), {})().fields), ["name"] + ) + self.assertEqual( + list(type("NewForm", (ModelForm, Mixin, Form), {})().fields), ["name"] + ) + self.assertEqual( + list(type("NewForm", (ModelForm, Form, Mixin), {})().fields), + ["name", "age"], + ) + self.assertEqual( + list(type("NewForm", (ModelForm, Form), {"age": None})().fields), ["name"] + ) def test_field_removal_name_clashes(self): """ Form fields can be removed in subclasses by setting them to None (#22510). """ + class MyForm(forms.ModelForm): media = forms.CharField() class Meta: model = Writer - fields = '__all__' + fields = "__all__" class SubForm(MyForm): media = None - self.assertIn('media', MyForm().fields) - self.assertNotIn('media', SubForm().fields) - self.assertTrue(hasattr(MyForm, 'media')) - self.assertTrue(hasattr(SubForm, 'media')) + self.assertIn("media", MyForm().fields) + self.assertNotIn("media", SubForm().fields) + self.assertTrue(hasattr(MyForm, "media")) + self.assertTrue(hasattr(SubForm, "media")) class StumpJokeForm(forms.ModelForm): class Meta: model = StumpJoke - fields = '__all__' + fields = "__all__" class CustomFieldWithQuerysetButNoLimitChoicesTo(forms.Field): @@ -2795,14 +3167,15 @@ class LimitChoicesToTests(TestCase): """ Tests the functionality of ``limit_choices_to``. """ + @classmethod def setUpTestData(cls): cls.threepwood = Character.objects.create( - username='threepwood', + username="threepwood", last_action=datetime.datetime.today() + datetime.timedelta(days=1), ) cls.marley = Character.objects.create( - username='marley', + username="marley", last_action=datetime.datetime.today() - datetime.timedelta(days=1), ) @@ -2811,14 +3184,18 @@ class LimitChoicesToTests(TestCase): A ForeignKey can use limit_choices_to as a callable (#2554). """ stumpjokeform = StumpJokeForm() - self.assertSequenceEqual(stumpjokeform.fields['most_recently_fooled'].queryset, [self.threepwood]) + self.assertSequenceEqual( + stumpjokeform.fields["most_recently_fooled"].queryset, [self.threepwood] + ) def test_limit_choices_to_callable_for_m2m_rel(self): """ A ManyToManyField can use limit_choices_to as a callable (#2554). """ stumpjokeform = StumpJokeForm() - self.assertSequenceEqual(stumpjokeform.fields['most_recently_fooled'].queryset, [self.threepwood]) + self.assertSequenceEqual( + stumpjokeform.fields["most_recently_fooled"].queryset, [self.threepwood] + ) def test_custom_field_with_queryset_but_no_limit_choices_to(self): """ @@ -2826,15 +3203,15 @@ class LimitChoicesToTests(TestCase): works (#23795). """ f = StumpJokeWithCustomFieldForm() - self.assertEqual(f.fields['custom'].queryset, 42) + self.assertEqual(f.fields["custom"].queryset, 42) def test_fields_for_model_applies_limit_choices_to(self): - fields = fields_for_model(StumpJoke, ['has_fooled_today']) - self.assertSequenceEqual(fields['has_fooled_today'].queryset, [self.threepwood]) + fields = fields_for_model(StumpJoke, ["has_fooled_today"]) + self.assertSequenceEqual(fields["has_fooled_today"].queryset, [self.threepwood]) def test_callable_called_each_time_form_is_instantiated(self): - field = StumpJokeForm.base_fields['most_recently_fooled'] - with mock.patch.object(field, 'limit_choices_to') as today_callable_dict: + field = StumpJokeForm.base_fields["most_recently_fooled"] + with mock.patch.object(field, "limit_choices_to") as today_callable_dict: StumpJokeForm() self.assertEqual(today_callable_dict.call_count, 1) StumpJokeForm() @@ -2842,7 +3219,7 @@ class LimitChoicesToTests(TestCase): StumpJokeForm() self.assertEqual(today_callable_dict.call_count, 3) - @isolate_apps('model_forms') + @isolate_apps("model_forms") def test_limit_choices_to_no_duplicates(self): joke1 = StumpJoke.objects.create( funny=True, @@ -2869,16 +3246,16 @@ class LimitChoicesToTests(TestCase): jokes__funny=True, jokes_today__funny=True, ), - related_name='details_fk_1', + related_name="details_fk_1", ) character2 = models.ForeignKey( Character, models.CASCADE, limit_choices_to={ - 'jokes__funny': True, - 'jokes_today__funny': True, + "jokes__funny": True, + "jokes_today__funny": True, }, - related_name='details_fk_2', + related_name="details_fk_2", ) character3 = models.ManyToManyField( Character, @@ -2886,25 +3263,25 @@ class LimitChoicesToTests(TestCase): jokes__funny=True, jokes_today__funny=True, ), - related_name='details_m2m_1', + related_name="details_m2m_1", ) class CharacterDetailsForm(forms.ModelForm): class Meta: model = CharacterDetails - fields = '__all__' + fields = "__all__" form = CharacterDetailsForm() self.assertCountEqual( - form.fields['character1'].queryset, + form.fields["character1"].queryset, [self.marley, self.threepwood], ) self.assertCountEqual( - form.fields['character2'].queryset, + form.fields["character2"].queryset, [self.marley, self.threepwood], ) self.assertCountEqual( - form.fields['character3'].queryset, + form.fields["character3"].queryset, [self.marley, self.threepwood], ) @@ -2912,18 +3289,17 @@ class LimitChoicesToTests(TestCase): class DiceForm(forms.ModelForm): class Meta: model = Dice - fields = ['numbers'] + fields = ["numbers"] Number.objects.create(value=0) n1 = Number.objects.create(value=1) n2 = Number.objects.create(value=2) form = DiceForm() - self.assertCountEqual(form.fields['numbers'].queryset, [n1, n2]) + self.assertCountEqual(form.fields["numbers"].queryset, [n1, n2]) class FormFieldCallbackTests(SimpleTestCase): - def test_baseform_with_widgets_in_meta(self): """Regression for #13095: Using base forms with widgets defined in Meta should not raise errors.""" widget = forms.Textarea() @@ -2931,28 +3307,28 @@ class FormFieldCallbackTests(SimpleTestCase): class BaseForm(forms.ModelForm): class Meta: model = Person - widgets = {'name': widget} + widgets = {"name": widget} fields = "__all__" Form = modelform_factory(Person, form=BaseForm) - self.assertIsInstance(Form.base_fields['name'].widget, forms.Textarea) + self.assertIsInstance(Form.base_fields["name"].widget, forms.Textarea) def test_factory_with_widget_argument(self): - """ Regression for #15315: modelform_factory should accept widgets - argument + """Regression for #15315: modelform_factory should accept widgets + argument """ widget = forms.Textarea() # Without a widget should not set the widget to textarea Form = modelform_factory(Person, fields="__all__") - self.assertNotEqual(Form.base_fields['name'].widget.__class__, forms.Textarea) + self.assertNotEqual(Form.base_fields["name"].widget.__class__, forms.Textarea) # With a widget should not set the widget to textarea - Form = modelform_factory(Person, fields="__all__", widgets={'name': widget}) - self.assertEqual(Form.base_fields['name'].widget.__class__, forms.Textarea) + Form = modelform_factory(Person, fields="__all__", widgets={"name": widget}) + self.assertEqual(Form.base_fields["name"].widget.__class__, forms.Textarea) def test_modelform_factory_without_fields(self): - """ Regression for #19733 """ + """Regression for #19733""" message = ( "Calling modelform_factory without defining 'fields' or 'exclude' " "explicitly is prohibited." @@ -2961,7 +3337,7 @@ class FormFieldCallbackTests(SimpleTestCase): modelform_factory(Person) def test_modelform_factory_with_all_fields(self): - """ Regression for #19733 """ + """Regression for #19733""" form = modelform_factory(Person, fields="__all__") self.assertEqual(list(form.base_fields), ["name"]) @@ -2978,18 +3354,24 @@ class FormFieldCallbackTests(SimpleTestCase): class BaseForm(forms.ModelForm): class Meta: model = Person - widgets = {'name': widget} + widgets = {"name": widget} fields = "__all__" modelform_factory(Person, form=BaseForm, formfield_callback=callback) id_field, name_field = Person._meta.fields - self.assertEqual(callback_args, [(id_field, {}), (name_field, {'widget': widget})]) + self.assertEqual( + callback_args, [(id_field, {}), (name_field, {"widget": widget})] + ) def test_bad_callback(self): # A bad callback provided by user still gives an error with self.assertRaises(TypeError): - modelform_factory(Person, fields="__all__", formfield_callback='not a function or callable') + modelform_factory( + Person, + fields="__all__", + formfield_callback="not a function or callable", + ) def test_inherit_after_custom_callback(self): def callback(db_field, **kwargs): @@ -3000,7 +3382,7 @@ class FormFieldCallbackTests(SimpleTestCase): class BaseForm(forms.ModelForm): class Meta: model = Person - fields = '__all__' + fields = "__all__" NewForm = modelform_factory(Person, form=BaseForm, formfield_callback=callback) @@ -3010,7 +3392,7 @@ class FormFieldCallbackTests(SimpleTestCase): for name in NewForm.base_fields: self.assertEqual( type(InheritedForm.base_fields[name].widget), - type(NewForm.base_fields[name].widget) + type(NewForm.base_fields[name].widget), ) @@ -3019,27 +3401,30 @@ class LocalizedModelFormTest(TestCase): class PartiallyLocalizedTripleForm(forms.ModelForm): class Meta: model = Triple - localized_fields = ('left', 'right',) - fields = '__all__' + localized_fields = ( + "left", + "right", + ) + fields = "__all__" - f = PartiallyLocalizedTripleForm({'left': 10, 'middle': 10, 'right': 10}) + f = PartiallyLocalizedTripleForm({"left": 10, "middle": 10, "right": 10}) self.assertTrue(f.is_valid()) - self.assertTrue(f.fields['left'].localize) - self.assertFalse(f.fields['middle'].localize) - self.assertTrue(f.fields['right'].localize) + self.assertTrue(f.fields["left"].localize) + self.assertFalse(f.fields["middle"].localize) + self.assertTrue(f.fields["right"].localize) def test_model_form_applies_localize_to_all_fields(self): class FullyLocalizedTripleForm(forms.ModelForm): class Meta: model = Triple - localized_fields = '__all__' - fields = '__all__' + localized_fields = "__all__" + fields = "__all__" - f = FullyLocalizedTripleForm({'left': 10, 'middle': 10, 'right': 10}) + f = FullyLocalizedTripleForm({"left": 10, "middle": 10, "right": 10}) self.assertTrue(f.is_valid()) - self.assertTrue(f.fields['left'].localize) - self.assertTrue(f.fields['middle'].localize) - self.assertTrue(f.fields['right'].localize) + self.assertTrue(f.fields["left"].localize) + self.assertTrue(f.fields["middle"].localize) + self.assertTrue(f.fields["right"].localize) def test_model_form_refuses_arbitrary_string(self): msg = ( @@ -3047,6 +3432,7 @@ class LocalizedModelFormTest(TestCase): "cannot be a string. Did you mean to type: ('foo',)?" ) with self.assertRaisesMessage(TypeError, msg): + class BrokenLocalizedTripleForm(forms.ModelForm): class Meta: model = Triple @@ -3081,41 +3467,47 @@ class StrictAssignmentTests(SimpleTestCase): A model ValidationError using the dict form should put the error message into the correct key of form.errors. """ - form_class = modelform_factory(model=StrictAssignmentFieldSpecific, fields=['title']) - form = form_class(data={'title': 'testing setattr'}, files=None) + form_class = modelform_factory( + model=StrictAssignmentFieldSpecific, fields=["title"] + ) + form = form_class(data={"title": "testing setattr"}, files=None) # This line turns on the ValidationError; it avoids the model erroring # when its own __init__() is called when creating form.instance. form.instance._should_error = True self.assertFalse(form.is_valid()) - self.assertEqual(form.errors, { - 'title': ['Cannot set attribute', 'This field cannot be blank.'] - }) + self.assertEqual( + form.errors, + {"title": ["Cannot set attribute", "This field cannot be blank."]}, + ) def test_setattr_raises_validation_error_non_field(self): """ A model ValidationError not using the dict form should put the error message into __all__ (i.e. non-field errors) on the form. """ - form_class = modelform_factory(model=StrictAssignmentAll, fields=['title']) - form = form_class(data={'title': 'testing setattr'}, files=None) + form_class = modelform_factory(model=StrictAssignmentAll, fields=["title"]) + form = form_class(data={"title": "testing setattr"}, files=None) # This line turns on the ValidationError; it avoids the model erroring # when its own __init__() is called when creating form.instance. form.instance._should_error = True self.assertFalse(form.is_valid()) - self.assertEqual(form.errors, { - '__all__': ['Cannot set attribute'], - 'title': ['This field cannot be blank.'] - }) + self.assertEqual( + form.errors, + { + "__all__": ["Cannot set attribute"], + "title": ["This field cannot be blank."], + }, + ) class ModelToDictTests(TestCase): def test_many_to_many(self): """Data for a ManyToManyField is a list rather than a lazy QuerySet.""" - blue = Colour.objects.create(name='blue') - red = Colour.objects.create(name='red') + blue = Colour.objects.create(name="blue") + red = Colour.objects.create(name="red") item = ColourfulItem.objects.create() item.colours.set([blue]) - data = model_to_dict(item)['colours'] + data = model_to_dict(item)["colours"] self.assertEqual(data, [blue]) item.colours.set([red]) # If data were a QuerySet, it would be reevaluated here and give "red" |
