From f026a519aea8f3ea7ca339bfbbb007e1ee0068b0 Mon Sep 17 00:00:00 2001 From: Luke Plant Date: Thu, 21 Feb 2013 21:56:55 +0000 Subject: Fixed #19733 - deprecated ModelForms without 'fields' or 'exclude', and added '__all__' shortcut This also updates all dependent functionality, including modelform_factory and modelformset_factory, and the generic views `ModelFormMixin`, `CreateView` and `UpdateView` which gain a new `fields` attribute. --- tests/admin_validation/tests.py | 2 + tests/bug639/models.py | 1 + tests/foreign_object/tests.py | 1 + tests/forms_tests/tests/test_regressions.py | 1 + tests/forms_tests/tests/tests.py | 4 + tests/generic_relations/tests.py | 1 + tests/generic_views/test_edit.py | 44 ++++++++++- tests/generic_views/test_forms.py | 1 + tests/generic_views/views.py | 9 +++ tests/i18n/forms.py | 1 + tests/inline_formsets/tests.py | 10 +-- tests/model_forms/tests.py | 111 +++++++++++++++++++++++++--- tests/model_forms_regress/tests.py | 57 ++++++++++++-- tests/model_formsets/tests.py | 89 +++++++++++----------- tests/model_formsets_regress/tests.py | 28 +++---- tests/model_inheritance_regress/tests.py | 2 + tests/modeladmin/tests.py | 9 +-- tests/timezones/forms.py | 1 + 18 files changed, 283 insertions(+), 89 deletions(-) (limited to 'tests') diff --git a/tests/admin_validation/tests.py b/tests/admin_validation/tests.py index 6ce0ee7e03..16f73c6390 100644 --- a/tests/admin_validation/tests.py +++ b/tests/admin_validation/tests.py @@ -285,6 +285,8 @@ class ValidationTestCase(TestCase): extra_data = forms.CharField() class Meta: model = Song + fields = '__all__' + class FieldsOnFormOnlyAdmin(admin.ModelAdmin): form = SongForm diff --git a/tests/bug639/models.py b/tests/bug639/models.py index e641555c87..fa8e7d2c07 100644 --- a/tests/bug639/models.py +++ b/tests/bug639/models.py @@ -25,3 +25,4 @@ class Photo(models.Model): class PhotoForm(ModelForm): class Meta: model = Photo + fields = '__all__' diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py index 2ca13cb786..55dd6a0f47 100644 --- a/tests/foreign_object/tests.py +++ b/tests/foreign_object/tests.py @@ -322,6 +322,7 @@ class FormsTests(TestCase): class ArticleForm(forms.ModelForm): class Meta: model = Article + fields = '__all__' def test_foreign_object_form(self): # A very crude test checking that the non-concrete fields do not get form fields. diff --git a/tests/forms_tests/tests/test_regressions.py b/tests/forms_tests/tests/test_regressions.py index be9dc8c593..74509a0f1a 100644 --- a/tests/forms_tests/tests/test_regressions.py +++ b/tests/forms_tests/tests/test_regressions.py @@ -139,6 +139,7 @@ class FormsRegressionsTestCase(TestCase): class CheeseForm(ModelForm): class Meta: model = Cheese + fields = '__all__' form = CheeseForm({ 'name': 'Brie', diff --git a/tests/forms_tests/tests/tests.py b/tests/forms_tests/tests/tests.py index 80e2cadcc3..deda4822b8 100644 --- a/tests/forms_tests/tests/tests.py +++ b/tests/forms_tests/tests/tests.py @@ -17,11 +17,13 @@ from ..models import (ChoiceOptionModel, ChoiceFieldModel, FileModel, Group, class ChoiceFieldForm(ModelForm): class Meta: model = ChoiceFieldModel + fields = '__all__' class OptionalMultiChoiceModelForm(ModelForm): class Meta: model = OptionalMultiChoiceModel + fields = '__all__' class FileForm(Form): @@ -139,6 +141,7 @@ class FormsModelTestCase(TestCase): class BoundaryForm(ModelForm): class Meta: model = BoundaryModel + fields = '__all__' f = BoundaryForm({'positive_integer': 100}) self.assertTrue(f.is_valid()) @@ -154,6 +157,7 @@ class FormsModelTestCase(TestCase): class DefaultsForm(ModelForm): class Meta: model = Defaults + fields = '__all__' self.assertEqual(DefaultsForm().fields['name'].initial, 'class default value') self.assertEqual(DefaultsForm().fields['def_date'].initial, datetime.date(1980, 1, 1)) diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index 27b25185ea..dd9dc506ca 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -247,6 +247,7 @@ class CustomWidget(forms.TextInput): class TaggedItemForm(forms.ModelForm): class Meta: model = TaggedItem + fields = '__all__' widgets = {'tag': CustomWidget} class GenericInlineFormsetTest(TestCase): diff --git a/tests/generic_views/test_edit.py b/tests/generic_views/test_edit.py index c54d632363..54eab7ffa4 100644 --- a/tests/generic_views/test_edit.py +++ b/tests/generic_views/test_edit.py @@ -1,12 +1,14 @@ from __future__ import absolute_import +import warnings + from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import reverse from django import forms from django.test import TestCase from django.utils.unittest import expectedFailure from django.views.generic.base import View -from django.views.generic.edit import FormMixin +from django.views.generic.edit import FormMixin, CreateView, UpdateView from . import views from .models import Artist, Author @@ -34,6 +36,7 @@ class ModelFormMixinTests(TestCase): form_class = views.AuthorGetQuerySetFormView().get_form_class() self.assertEqual(form_class._meta.model, Author) + class CreateViewTests(TestCase): urls = 'generic_views.urls' @@ -112,6 +115,45 @@ class CreateViewTests(TestCase): self.assertEqual(res.status_code, 302) self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/') + def test_create_view_with_restricted_fields(self): + + class MyCreateView(CreateView): + model = Author + fields = ['name'] + + self.assertEqual(list(MyCreateView().get_form_class().base_fields), + ['name']) + + def test_create_view_all_fields(self): + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", PendingDeprecationWarning) + + class MyCreateView(CreateView): + model = Author + fields = '__all__' + + self.assertEqual(list(MyCreateView().get_form_class().base_fields), + ['name', 'slug']) + self.assertEqual(len(w), 0) + + + def test_create_view_without_explicit_fields(self): + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", PendingDeprecationWarning) + + class MyCreateView(CreateView): + model = Author + + # Until end of the deprecation cycle, should still create the form + # as before: + self.assertEqual(list(MyCreateView().get_form_class().base_fields), + ['name', 'slug']) + + # but with a warning: + self.assertEqual(w[0].category, PendingDeprecationWarning) + class UpdateViewTests(TestCase): urls = 'generic_views.urls' diff --git a/tests/generic_views/test_forms.py b/tests/generic_views/test_forms.py index e036ad8afc..8c118e32a6 100644 --- a/tests/generic_views/test_forms.py +++ b/tests/generic_views/test_forms.py @@ -11,6 +11,7 @@ class AuthorForm(forms.ModelForm): class Meta: model = Author + fields = ['name', 'slug'] class ContactForm(forms.Form): diff --git a/tests/generic_views/views.py b/tests/generic_views/views.py index 69bfcb32dd..aa8777e8c6 100644 --- a/tests/generic_views/views.py +++ b/tests/generic_views/views.py @@ -85,15 +85,18 @@ class ContactView(generic.FormView): class ArtistCreate(generic.CreateView): model = Artist + fields = '__all__' class NaiveAuthorCreate(generic.CreateView): queryset = Author.objects.all() + fields = '__all__' class AuthorCreate(generic.CreateView): model = Author success_url = '/list/authors/' + fields = '__all__' class SpecializedAuthorCreate(generic.CreateView): @@ -112,19 +115,23 @@ class AuthorCreateRestricted(AuthorCreate): class ArtistUpdate(generic.UpdateView): model = Artist + fields = '__all__' class NaiveAuthorUpdate(generic.UpdateView): queryset = Author.objects.all() + fields = '__all__' class AuthorUpdate(generic.UpdateView): model = Author success_url = '/list/authors/' + fields = '__all__' class OneAuthorUpdate(generic.UpdateView): success_url = '/list/authors/' + fields = '__all__' def get_object(self): return Author.objects.get(pk=1) @@ -184,6 +191,8 @@ class BookDetail(BookConfig, generic.DateDetailView): pass class AuthorGetQuerySetFormView(generic.edit.ModelFormMixin): + fields = '__all__' + def get_queryset(self): return Author.objects.all() diff --git a/tests/i18n/forms.py b/tests/i18n/forms.py index abb99f443a..6e4def9c5e 100644 --- a/tests/i18n/forms.py +++ b/tests/i18n/forms.py @@ -24,3 +24,4 @@ class CompanyForm(forms.ModelForm): class Meta: model = Company + fields = '__all__' diff --git a/tests/inline_formsets/tests.py b/tests/inline_formsets/tests.py index df682d34ef..ad8a666cb5 100644 --- a/tests/inline_formsets/tests.py +++ b/tests/inline_formsets/tests.py @@ -10,7 +10,7 @@ from .models import Poet, Poem, School, Parent, Child class DeletionTests(TestCase): def test_deletion(self): - PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True) + PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True, fields="__all__") poet = Poet.objects.create(name='test') poem = poet.poem_set.create(name='test poem') data = { @@ -32,7 +32,7 @@ class DeletionTests(TestCase): Make sure that an add form that is filled out, but marked for deletion doesn't cause validation errors. """ - PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True) + PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True, fields="__all__") poet = Poet.objects.create(name='test') data = { 'poem_set-TOTAL_FORMS': '1', @@ -60,7 +60,7 @@ class DeletionTests(TestCase): Make sure that a change form that is filled out, but marked for deletion doesn't cause validation errors. """ - PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True) + PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True, fields="__all__") poet = Poet.objects.create(name='test') poem = poet.poem_set.create(name='test poem') data = { @@ -115,8 +115,8 @@ class InlineFormsetFactoryTest(TestCase): """ These should both work without a problem. """ - inlineformset_factory(Parent, Child, fk_name='mother') - inlineformset_factory(Parent, Child, fk_name='father') + inlineformset_factory(Parent, Child, fk_name='mother', fields="__all__") + inlineformset_factory(Parent, Child, fk_name='father', fields="__all__") def test_exception_on_unspecified_foreign_key(self): """ diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index 96c3ecbdce..c5db011404 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals import datetime import os from decimal import Decimal +import warnings from django import forms from django.core.exceptions import FieldError @@ -30,19 +31,25 @@ if test_images: class ImageFileForm(forms.ModelForm): class Meta: model = ImageFile + fields = '__all__' + class OptionalImageFileForm(forms.ModelForm): class Meta: model = OptionalImageFile + fields = '__all__' + class ProductForm(forms.ModelForm): class Meta: model = Product + fields = '__all__' class PriceForm(forms.ModelForm): class Meta: model = Price + fields = '__all__' class BookForm(forms.ModelForm): @@ -66,11 +73,13 @@ class ExplicitPKForm(forms.ModelForm): class PostForm(forms.ModelForm): class Meta: model = Post + fields = '__all__' class DerivedPostForm(forms.ModelForm): class Meta: model = DerivedPost + fields = '__all__' class CustomAuthorForm(forms.ModelForm): @@ -78,61 +87,79 @@ class CustomAuthorForm(forms.ModelForm): class Meta: model = Author + fields = '__all__' class FlexDatePostForm(forms.ModelForm): class Meta: model = FlexibleDatePost + fields = '__all__' class BaseCategoryForm(forms.ModelForm): class Meta: model = Category + fields = '__all__' class ArticleForm(forms.ModelForm): class Meta: model = Article + fields = '__all__' class ArticleForm(forms.ModelForm): class Meta: model = Article + fields = '__all__' + class PartialArticleForm(forms.ModelForm): class Meta: model = Article fields = ('headline','pub_date') + class RoykoForm(forms.ModelForm): class Meta: model = Author + fields = '__all__' + class TestArticleForm(forms.ModelForm): class Meta: model = Article + fields = '__all__' + class PartialArticleFormWithSlug(forms.ModelForm): class Meta: model = Article - fields=('headline', 'slug', 'pub_date') + fields = ('headline', 'slug', 'pub_date') + class ArticleStatusForm(forms.ModelForm): class Meta: model = ArticleStatus + fields = '__all__' + class InventoryForm(forms.ModelForm): class Meta: model = Inventory + fields = '__all__' + class SelectInventoryForm(forms.Form): items = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode') + class CustomFieldForExclusionForm(forms.ModelForm): class Meta: model = CustomFieldForExclusionModel fields = ['name', 'markup'] + class ShortCategory(forms.ModelForm): name = forms.CharField(max_length=5) slug = forms.CharField(max_length=5) @@ -140,30 +167,44 @@ class ShortCategory(forms.ModelForm): class Meta: model = Category + fields = '__all__' + class ImprovedArticleForm(forms.ModelForm): class Meta: model = ImprovedArticle + fields = '__all__' + class ImprovedArticleWithParentLinkForm(forms.ModelForm): class Meta: model = ImprovedArticleWithParentLink + fields = '__all__' + class BetterAuthorForm(forms.ModelForm): class Meta: model = BetterAuthor + fields = '__all__' + class AuthorProfileForm(forms.ModelForm): class Meta: model = AuthorProfile + fields = '__all__' + class TextFileForm(forms.ModelForm): class Meta: model = TextFile + fields = '__all__' + class BigIntForm(forms.ModelForm): class Meta: model = BigInt + fields = '__all__' + class ModelFormWithMedia(forms.ModelForm): class Media: @@ -173,19 +214,25 @@ class ModelFormWithMedia(forms.ModelForm): } class Meta: model = TextFile + fields = '__all__' + class CommaSeparatedIntegerForm(forms.ModelForm): - class Meta: - model = CommaSeparatedInteger + class Meta: + model = CommaSeparatedInteger + fields = '__all__' + class PriceFormWithoutQuantity(forms.ModelForm): class Meta: model = Price exclude = ('quantity',) + class ColourfulItemForm(forms.ModelForm): class Meta: model = ColourfulItem + fields = '__all__' class ModelFormBaseTest(TestCase): @@ -193,6 +240,25 @@ class ModelFormBaseTest(TestCase): self.assertEqual(list(BaseCategoryForm.base_fields), ['name', 'slug', 'url']) + def test_missing_fields_attribute(self): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", PendingDeprecationWarning) + + class MissingFieldsForm(forms.ModelForm): + class Meta: + model = Category + + # There is some internal state in warnings module which means that + # if a warning has been seen already, the catch_warnings won't + # have recorded it. The following line therefore will not work reliably: + + # self.assertEqual(w[0].category, PendingDeprecationWarning) + + # Until end of the deprecation cycle, should still create the + # form as before: + self.assertEqual(list(MissingFieldsForm.base_fields), + ['name', 'slug', 'url']) + def test_extra_fields(self): class ExtraFields(BaseCategoryForm): some_extra_field = forms.BooleanField() @@ -206,6 +272,33 @@ class ModelFormBaseTest(TestCase): class Meta: model = Category + fields = '__all__' + + self.assertTrue(isinstance(ReplaceField.base_fields['url'], + forms.fields.BooleanField)) + + def test_replace_field_variant_2(self): + # Should have the same result as before, + # but 'fields' attribute specified differently + class ReplaceField(forms.ModelForm): + url = forms.BooleanField() + + class Meta: + model = Category + fields = ['url'] + + self.assertTrue(isinstance(ReplaceField.base_fields['url'], + forms.fields.BooleanField)) + + def test_replace_field_variant_3(self): + # Should have the same result as before, + # but 'fields' attribute specified differently + class ReplaceField(forms.ModelForm): + url = forms.BooleanField() + + class Meta: + model = Category + fields = [] # url will still appear, since it is explicit above self.assertTrue(isinstance(ReplaceField.base_fields['url'], forms.fields.BooleanField)) @@ -216,19 +309,11 @@ class ModelFormBaseTest(TestCase): class Meta: model = Author + fields = '__all__' wf = AuthorForm({'name': 'Richard Lockridge'}) self.assertTrue(wf.is_valid()) - def test_limit_fields(self): - class LimitFields(forms.ModelForm): - class Meta: - model = Category - fields = ['url'] - - self.assertEqual(list(LimitFields.base_fields), - ['url']) - def test_limit_nonexistent_field(self): expected_msg = 'Unknown field(s) (nonexistent) specified for Category' with self.assertRaisesMessage(FieldError, expected_msg): @@ -294,6 +379,7 @@ class ModelFormBaseTest(TestCase): """ class Meta: model = Article + fields = '__all__' # MixModelForm is now an Article-related thing, because MixModelForm.Meta # overrides BaseCategoryForm.Meta. @@ -348,6 +434,7 @@ class ModelFormBaseTest(TestCase): class Meta: model = Category + fields = '__all__' class SubclassMeta(SomeCategoryForm): """ We can also subclass the Meta inner class to change the fields diff --git a/tests/model_forms_regress/tests.py b/tests/model_forms_regress/tests.py index 90c907f2a6..3f15c35938 100644 --- a/tests/model_forms_regress/tests.py +++ b/tests/model_forms_regress/tests.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, unicode_literals from datetime import date +import warnings from django import forms from django.core.exceptions import FieldError, ValidationError @@ -43,9 +44,12 @@ class ModelMultipleChoiceFieldTests(TestCase): f.clean([p.pk for p in Person.objects.all()[8:9]]) self.assertTrue(self._validator_run) + class TripleForm(forms.ModelForm): class Meta: model = Triple + fields = '__all__' + class UniqueTogetherTests(TestCase): def test_multiple_field_unique_together(self): @@ -63,15 +67,18 @@ class UniqueTogetherTests(TestCase): form = TripleForm({'left': '1', 'middle': '3', 'right': '1'}) self.assertTrue(form.is_valid()) + class TripleFormWithCleanOverride(forms.ModelForm): class Meta: model = Triple + fields = '__all__' def clean(self): if not self.cleaned_data['left'] == self.cleaned_data['right']: raise forms.ValidationError('Left and right should be equal') return self.cleaned_data + class OverrideCleanTests(TestCase): def test_override_clean(self): """ @@ -84,6 +91,7 @@ class OverrideCleanTests(TestCase): # by form.full_clean(). self.assertEqual(form.instance.left, 1) + # Regression test for #12960. # Make sure the cleaned_data returned from ModelForm.clean() is applied to the # model instance. @@ -95,6 +103,8 @@ class PublicationForm(forms.ModelForm): class Meta: model = Publication + fields = '__all__' + class ModelFormCleanTest(TestCase): def test_model_form_clean_applies_to_model(self): @@ -103,9 +113,12 @@ class ModelFormCleanTest(TestCase): publication = form.save() self.assertEqual(publication.title, 'TEST') + class FPForm(forms.ModelForm): class Meta: model = FilePathModel + fields = '__all__' + class FilePathFieldTests(TestCase): def test_file_path_field_blank(self): @@ -133,7 +146,8 @@ class ManyToManyCallableInitialTests(TestCase): book3 = Publication.objects.create(title="Third Book", date_published=date(2009,1,1)) # Create a ModelForm, instantiate it, and check that the output is as expected - ModelForm = modelform_factory(Article, formfield_callback=formfield_for_dbfield) + ModelForm = modelform_factory(Article, fields="__all__", + formfield_callback=formfield_for_dbfield) form = ModelForm() self.assertHTMLEqual(form.as_ul(), """
  • Hold down "Control", or "Command" on a Mac, to select more than one.
  • """ % (book1.pk, book2.pk, book3.pk)) + class CFFForm(forms.ModelForm): class Meta: model = CustomFF + fields = '__all__' + class CustomFieldSaveTests(TestCase): def test_save(self): @@ -168,9 +185,12 @@ class ModelChoiceIteratorTests(TestCase): f = Form() self.assertEqual(len(f.fields["publications"].choices), 1) + class RealPersonForm(forms.ModelForm): class Meta: model = RealPerson + fields = '__all__' + class CustomModelFormSaveMethod(TestCase): def test_string_message(self): @@ -230,9 +250,12 @@ class TestTicket11183(TestCase): self.assertTrue(field1 is not ModelChoiceForm.base_fields['person']) self.assertTrue(field1.widget.choices.field is field1) + class HomepageForm(forms.ModelForm): class Meta: model = Homepage + fields = '__all__' + class URLFieldTests(TestCase): def test_url_on_modelform(self): @@ -274,6 +297,7 @@ class FormFieldCallbackTests(TestCase): class Meta: model = Person widgets = {'name': widget} + fields = "__all__" Form = modelform_factory(Person, form=BaseForm) self.assertTrue(Form.base_fields['name'].widget is widget) @@ -285,11 +309,11 @@ class FormFieldCallbackTests(TestCase): widget = forms.Textarea() # Without a widget should not set the widget to textarea - Form = modelform_factory(Person) + Form = modelform_factory(Person, fields="__all__") self.assertNotEqual(Form.base_fields['name'].widget.__class__, forms.Textarea) # With a widget should not set the widget to textarea - Form = modelform_factory(Person, widgets={'name':widget}) + Form = modelform_factory(Person, fields="__all__", widgets={'name':widget}) self.assertEqual(Form.base_fields['name'].widget.__class__, forms.Textarea) def test_custom_callback(self): @@ -307,6 +331,7 @@ class FormFieldCallbackTests(TestCase): class Meta: model = Person widgets = {'name': widget} + fields = "__all__" _ = modelform_factory(Person, form=BaseForm, formfield_callback=callback) @@ -317,7 +342,7 @@ class FormFieldCallbackTests(TestCase): def test_bad_callback(self): # A bad callback provided by user still gives an error - self.assertRaises(TypeError, modelform_factory, Person, + self.assertRaises(TypeError, modelform_factory, Person, fields="__all__", formfield_callback='not a function or callable') @@ -362,6 +387,8 @@ class InvalidFieldAndFactory(TestCase): class DocumentForm(forms.ModelForm): class Meta: model = Document + fields = '__all__' + class FileFieldTests(unittest.TestCase): def test_clean_false(self): @@ -425,6 +452,7 @@ class FileFieldTests(unittest.TestCase): self.assertTrue('something.txt' in rendered) self.assertTrue('myfile-clear' in rendered) + class EditionForm(forms.ModelForm): author = forms.ModelChoiceField(queryset=Person.objects.all()) publication = forms.ModelChoiceField(queryset=Publication.objects.all()) @@ -433,6 +461,8 @@ class EditionForm(forms.ModelForm): class Meta: model = Edition + fields = '__all__' + class UniqueErrorsTests(TestCase): def setUp(self): @@ -473,7 +503,7 @@ class EmptyFieldsTestCase(TestCase): def test_empty_fields_to_construct_instance(self): "No fields should be set on a model instance if construct_instance receives fields=()" - form = modelform_factory(Person)({'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, '') @@ -485,10 +515,25 @@ class CustomMetaclass(ModelFormMetaclass): new.base_fields = {} return new + class CustomMetaclassForm(six.with_metaclass(CustomMetaclass, forms.ModelForm)): pass + class CustomMetaclassTestCase(TestCase): def test_modelform_factory_metaclass(self): - new_cls = modelform_factory(Person, form=CustomMetaclassForm) + new_cls = modelform_factory(Person, fields="__all__", form=CustomMetaclassForm) self.assertEqual(new_cls.base_fields, {}) + + +class TestTicket19733(TestCase): + def test_modelform_factory_without_fields(self): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", PendingDeprecationWarning) + # This should become an error once deprecation cycle is complete. + form = modelform_factory(Person) + self.assertEqual(w[0].category, PendingDeprecationWarning) + + def test_modelform_factory_with_all_fields(self): + form = modelform_factory(Person, fields="__all__") + self.assertEqual(form.base_fields.keys(), ["name"]) diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py index 8d0c017a61..8cfdf53995 100644 --- a/tests/model_formsets/tests.py +++ b/tests/model_formsets/tests.py @@ -21,7 +21,7 @@ from .models import (Author, BetterAuthor, Book, BookWithCustomPK, class DeletionTests(TestCase): def test_deletion(self): - PoetFormSet = modelformset_factory(Poet, can_delete=True) + PoetFormSet = modelformset_factory(Poet, fields="__all__", can_delete=True) poet = Poet.objects.create(name='test') data = { 'form-TOTAL_FORMS': '1', @@ -41,7 +41,7 @@ class DeletionTests(TestCase): Make sure that an add form that is filled out, but marked for deletion doesn't cause validation errors. """ - PoetFormSet = modelformset_factory(Poet, can_delete=True) + PoetFormSet = modelformset_factory(Poet, fields="__all__", can_delete=True) poet = Poet.objects.create(name='test') # One existing untouched and two new unvalid forms data = { @@ -75,7 +75,7 @@ class DeletionTests(TestCase): Make sure that a change form that is filled out, but marked for deletion doesn't cause validation errors. """ - PoetFormSet = modelformset_factory(Poet, can_delete=True) + PoetFormSet = modelformset_factory(Poet, fields="__all__", can_delete=True) poet = Poet.objects.create(name='test') data = { 'form-TOTAL_FORMS': '1', @@ -100,7 +100,7 @@ class DeletionTests(TestCase): class ModelFormsetTest(TestCase): def test_simple_save(self): qs = Author.objects.all() - AuthorFormSet = modelformset_factory(Author, extra=3) + AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=3) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 3) @@ -138,7 +138,7 @@ class ModelFormsetTest(TestCase): # we'll use it to display them in alphabetical order by name. qs = Author.objects.order_by('name') - AuthorFormSet = modelformset_factory(Author, extra=1, can_delete=False) + AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=1, can_delete=False) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 3) @@ -176,7 +176,7 @@ class ModelFormsetTest(TestCase): # marked for deletion, make sure we don't save that form. qs = Author.objects.order_by('name') - AuthorFormSet = modelformset_factory(Author, extra=1, can_delete=True) + AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=1, can_delete=True) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 4) @@ -256,7 +256,7 @@ class ModelFormsetTest(TestCase): author4 = Author.objects.create(name='John Steinbeck') - AuthorMeetingFormSet = modelformset_factory(AuthorMeeting, extra=1, can_delete=True) + AuthorMeetingFormSet = modelformset_factory(AuthorMeeting, fields="__all__", extra=1, can_delete=True) data = { 'form-TOTAL_FORMS': '2', # the number of forms rendered 'form-INITIAL_FORMS': '1', # the number of forms with initial data @@ -294,22 +294,22 @@ class ModelFormsetTest(TestCase): qs = Author.objects.order_by('name') - AuthorFormSet = modelformset_factory(Author, max_num=None, extra=3) + AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=None, extra=3) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 6) self.assertEqual(len(formset.extra_forms), 3) - AuthorFormSet = modelformset_factory(Author, max_num=4, extra=3) + AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=4, extra=3) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 4) self.assertEqual(len(formset.extra_forms), 1) - AuthorFormSet = modelformset_factory(Author, max_num=0, extra=3) + AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=0, extra=3) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 3) self.assertEqual(len(formset.extra_forms), 0) - AuthorFormSet = modelformset_factory(Author, max_num=None) + AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=None) formset = AuthorFormSet(queryset=qs) self.assertQuerysetEqual(formset.get_queryset(), [ '', @@ -317,7 +317,7 @@ class ModelFormsetTest(TestCase): '', ]) - AuthorFormSet = modelformset_factory(Author, max_num=0) + AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=0) formset = AuthorFormSet(queryset=qs) self.assertQuerysetEqual(formset.get_queryset(), [ '', @@ -325,7 +325,7 @@ class ModelFormsetTest(TestCase): '', ]) - AuthorFormSet = modelformset_factory(Author, max_num=4) + AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=4) formset = AuthorFormSet(queryset=qs) self.assertQuerysetEqual(formset.get_queryset(), [ '', @@ -343,7 +343,7 @@ class ModelFormsetTest(TestCase): author.save() return author - PoetFormSet = modelformset_factory(Poet, form=PoetForm) + PoetFormSet = modelformset_factory(Poet, fields="__all__", form=PoetForm) data = { 'form-TOTAL_FORMS': '3', # the number of forms rendered @@ -387,7 +387,7 @@ class ModelFormsetTest(TestCase): self.assertFalse("subtitle" in formset.forms[0].fields) def test_model_inheritance(self): - BetterAuthorFormSet = modelformset_factory(BetterAuthor) + BetterAuthorFormSet = modelformset_factory(BetterAuthor, fields="__all__") formset = BetterAuthorFormSet() self.assertEqual(len(formset.forms), 1) self.assertHTMLEqual(formset.forms[0].as_p(), @@ -440,7 +440,7 @@ class ModelFormsetTest(TestCase): # We can also create a formset that is tied to a parent model. This is # how the admin system's edit inline functionality works. - AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=3) + AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=3, fields="__all__") author = Author.objects.create(name='Charles Baudelaire') formset = AuthorBooksFormSet(instance=author) @@ -474,7 +474,7 @@ class ModelFormsetTest(TestCase): # another one. This time though, an edit form will be available for # every existing book. - AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2) + AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2, fields="__all__") author = Author.objects.get(name='Charles Baudelaire') formset = AuthorBooksFormSet(instance=author) @@ -514,7 +514,7 @@ class ModelFormsetTest(TestCase): def test_inline_formsets_save_as_new(self): # The save_as_new parameter lets you re-associate the data to a new # instance. This is used in the admin for save_as functionality. - AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2) + AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2, fields="__all__") author = Author.objects.create(name='Charles Baudelaire') data = { @@ -553,7 +553,7 @@ class ModelFormsetTest(TestCase): # primary key that is not the fk to the parent object. self.maxDiff = 1024 - AuthorBooksFormSet2 = inlineformset_factory(Author, BookWithCustomPK, can_delete=False, extra=1) + AuthorBooksFormSet2 = inlineformset_factory(Author, BookWithCustomPK, can_delete=False, extra=1, fields="__all__") author = Author.objects.create(pk=1, name='Charles Baudelaire') formset = AuthorBooksFormSet2(instance=author) @@ -585,7 +585,7 @@ class ModelFormsetTest(TestCase): # Test inline formsets where the inline-edited object uses multi-table # inheritance, thus has a non AutoField yet auto-created primary key. - AuthorBooksFormSet3 = inlineformset_factory(Author, AlternateBook, can_delete=False, extra=1) + AuthorBooksFormSet3 = inlineformset_factory(Author, AlternateBook, can_delete=False, extra=1, fields="__all__") author = Author.objects.create(pk=1, name='Charles Baudelaire') formset = AuthorBooksFormSet3(instance=author) @@ -616,7 +616,7 @@ class ModelFormsetTest(TestCase): # Test inline formsets where the inline-edited object has a # unique_together constraint with a nullable member - AuthorBooksFormSet4 = inlineformset_factory(Author, BookWithOptionalAltEditor, can_delete=False, extra=2) + AuthorBooksFormSet4 = inlineformset_factory(Author, BookWithOptionalAltEditor, can_delete=False, extra=2, fields="__all__") author = Author.objects.create(pk=1, name='Charles Baudelaire') data = { @@ -640,7 +640,7 @@ class ModelFormsetTest(TestCase): self.assertEqual(book2.title, 'Les Fleurs du Mal') def test_inline_formsets_with_custom_save_method(self): - AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2) + AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2, fields="__all__") author = Author.objects.create(pk=1, name='Charles Baudelaire') book1 = Book.objects.create(pk=1, author=author, title='Les Paradis Artificiels') book2 = Book.objects.create(pk=2, author=author, title='Les Fleurs du Mal') @@ -655,7 +655,7 @@ class ModelFormsetTest(TestCase): poem.save() return poem - PoemFormSet = inlineformset_factory(Poet, Poem, form=PoemForm) + PoemFormSet = inlineformset_factory(Poet, Poem, form=PoemForm, fields="__all__") data = { 'poem_set-TOTAL_FORMS': '3', # the number of forms rendered @@ -732,7 +732,7 @@ class ModelFormsetTest(TestCase): def test_custom_pk(self): # We need to ensure that it is displayed - CustomPrimaryKeyFormSet = modelformset_factory(CustomPrimaryKey) + CustomPrimaryKeyFormSet = modelformset_factory(CustomPrimaryKey, fields="__all__") formset = CustomPrimaryKeyFormSet() self.assertEqual(len(formset.forms), 1) self.assertHTMLEqual(formset.forms[0].as_p(), @@ -743,7 +743,7 @@ class ModelFormsetTest(TestCase): place = Place.objects.create(pk=1, name='Giordanos', city='Chicago') - FormSet = inlineformset_factory(Place, Owner, extra=2, can_delete=False) + FormSet = inlineformset_factory(Place, Owner, extra=2, can_delete=False, fields="__all__") formset = FormSet(instance=place) self.assertEqual(len(formset.forms), 2) self.assertHTMLEqual(formset.forms[0].as_p(), @@ -799,7 +799,7 @@ class ModelFormsetTest(TestCase): # Ensure a custom primary key that is a ForeignKey or OneToOneField get rendered for the user to choose. - FormSet = modelformset_factory(OwnerProfile) + FormSet = modelformset_factory(OwnerProfile, fields="__all__") formset = FormSet() self.assertHTMLEqual(formset.forms[0].as_p(), '

    ' % (band2.id, self.band.id)) class AdminConcertForm(forms.ModelForm): - class Meta: - model = Concert + pass def __init__(self, *args, **kwargs): super(AdminConcertForm, self).__init__(*args, **kwargs) @@ -685,9 +681,6 @@ class ValidationTests(unittest.TestCase): class AdminBandForm(forms.ModelForm): delete = forms.BooleanField() - class Meta: - model = Band - class BandAdmin(ModelAdmin): form = AdminBandForm diff --git a/tests/timezones/forms.py b/tests/timezones/forms.py index 3c9c31167e..45fb1d080b 100644 --- a/tests/timezones/forms.py +++ b/tests/timezones/forms.py @@ -11,3 +11,4 @@ class EventSplitForm(forms.Form): class EventModelForm(forms.ModelForm): class Meta: model = Event + fields = '__all__' -- cgit v1.3