diff --git a/tests/generic_inline_admin/tests.py b/tests/generic_inline_admin/tests.py index 07670d288c..8ba24037d4 100644 --- a/tests/generic_inline_admin/tests.py +++ b/tests/generic_inline_admin/tests.py @@ -2,7 +2,6 @@ from django.contrib import admin from django.contrib.admin.sites import AdminSite from django.contrib.auth.models import User from django.contrib.contenttypes.admin import GenericTabularInline -from django.contrib.contenttypes.forms import generic_inlineformset_factory from django.contrib.contenttypes.models import ContentType from django.forms.formsets import DEFAULT_MAX_NUM from django.forms.models import ModelForm @@ -89,110 +88,6 @@ class GenericAdminViewTest(TestDataMixin, TestCase): response = self.client.post(url, post_data) self.assertEqual(response.status_code, 302) # redirect somewhere - def test_generic_inline_formset(self): - EpisodeMediaFormSet = generic_inlineformset_factory( - Media, - can_delete=False, - exclude=['description', 'keywords'], - extra=3, - ) - e = Episode.objects.get(name='This Week in Django') - - # Works with no queryset - formset = EpisodeMediaFormSet(instance=e) - self.assertEqual(len(formset.forms), 5) - self.assertHTMLEqual( - formset.forms[0].as_p(), - '

' - '

' - % self.mp3_media_pk - ) - self.assertHTMLEqual( - formset.forms[1].as_p(), - '

' - '

' - % self.png_media_pk - ) - self.assertHTMLEqual( - formset.forms[2].as_p(), - '

' - '' - '

' - ) - - # A queryset can be used to alter display ordering - formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url')) - self.assertEqual(len(formset.forms), 5) - self.assertHTMLEqual( - formset.forms[0].as_p(), - '

' - '' - '

' - % self.png_media_pk - ) - self.assertHTMLEqual( - formset.forms[1].as_p(), - '

' - '' - '

' - % self.mp3_media_pk - ) - self.assertHTMLEqual( - formset.forms[2].as_p(), - '

' - '

' - ) - - # Works with a queryset that omits items - formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png")) - self.assertEqual(len(formset.forms), 4) - self.assertHTMLEqual( - formset.forms[0].as_p(), - '

' - ' ' - '

' - % self.png_media_pk - ) - self.assertHTMLEqual( - formset.forms[1].as_p(), - '

' - '

' - ) - - def test_generic_inline_formset_factory(self): - # Regression test for #10522. - inline_formset = generic_inlineformset_factory(Media, exclude=('url',)) - - # Regression test for #12340. - e = Episode.objects.get(name='This Week in Django') - formset = inline_formset(instance=e) - self.assertTrue(formset.get_queryset().ordered) - @override_settings(ROOT_URLCONF='generic_inline_admin.urls') class GenericInlineAdminParametersTest(TestDataMixin, TestCase): diff --git a/tests/generic_relations/test_forms.py b/tests/generic_relations/test_forms.py new file mode 100644 index 0000000000..bed31034be --- /dev/null +++ b/tests/generic_relations/test_forms.py @@ -0,0 +1,202 @@ +from django import forms +from django.contrib.contenttypes.forms import generic_inlineformset_factory +from django.contrib.contenttypes.models import ContentType +from django.db import models +from django.test import TestCase +from django.test.utils import isolate_apps + +from .models import ( + Animal, ForProxyModelModel, Gecko, Mineral, ProxyRelatedModel, TaggedItem, +) + + +class CustomWidget(forms.TextInput): + pass + + +class TaggedItemForm(forms.ModelForm): + class Meta: + model = TaggedItem + fields = '__all__' + widgets = {'tag': CustomWidget} + + +class GenericInlineFormsetTests(TestCase): + + def test_output(self): + GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) + formset = GenericFormSet() + self.assertHTMLEqual( + ''.join(form.as_p() for form in formset.forms), + """

+

+ +

""" + ) + formset = GenericFormSet(instance=Animal()) + self.assertHTMLEqual( + ''.join(form.as_p() for form in formset.forms), + """

+

+

""" + ) + platypus = Animal.objects.create( + common_name='Platypus', latin_name='Ornithorhynchus anatinus', + ) + platypus.tags.create(tag='shiny') + GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) + formset = GenericFormSet(instance=platypus) + tagged_item_id = TaggedItem.objects.get(tag='shiny', object_id=platypus.id).id + self.assertHTMLEqual( + ''.join(form.as_p() for form in formset.forms), + """

+

+

+ +

+

+

+

+ +

""" % tagged_item_id + ) + lion = Animal.objects.create(common_name='Lion', latin_name='Panthera leo') + formset = GenericFormSet(instance=lion, prefix='x') + self.assertHTMLEqual( + ''.join(form.as_p() for form in formset.forms), + """

+

+

+

""" + ) + + def test_options(self): + TaggedItemFormSet = generic_inlineformset_factory( + TaggedItem, + can_delete=False, + exclude=['tag'], + extra=3, + ) + platypus = Animal.objects.create(common_name='Platypus', latin_name='Ornithorhynchus anatinus') + harmless = platypus.tags.create(tag='harmless') + mammal = platypus.tags.create(tag='mammal') + # Works without a queryset. + formset = TaggedItemFormSet(instance=platypus) + self.assertEqual(len(formset.forms), 5) + self.assertHTMLEqual( + formset.forms[0].as_p(), + '' % harmless.pk + ) + self.assertEqual(formset.forms[0].instance, harmless) + self.assertEqual(formset.forms[1].instance, mammal) + self.assertIsNone(formset.forms[2].instance.pk) + # A queryset can be used to alter display ordering. + formset = TaggedItemFormSet(instance=platypus, queryset=TaggedItem.objects.order_by('-tag')) + self.assertEqual(len(formset.forms), 5) + self.assertEqual(formset.forms[0].instance, mammal) + self.assertEqual(formset.forms[1].instance, harmless) + self.assertIsNone(formset.forms[2].instance.pk) + # A queryset that omits items. + formset = TaggedItemFormSet(instance=platypus, queryset=TaggedItem.objects.filter(tag__startswith='harm')) + self.assertEqual(len(formset.forms), 4) + self.assertEqual(formset.forms[0].instance, harmless) + self.assertIsNone(formset.forms[1].instance.pk) + + def test_get_queryset_ordering(self): + """ + BaseGenericInlineFormSet.get_queryset() adds default ordering, if + needed. + """ + inline_formset = generic_inlineformset_factory(TaggedItem, exclude=('tag',)) + formset = inline_formset(instance=Gecko.objects.create()) + self.assertIs(formset.get_queryset().ordered, True) + + def test_initial(self): + quartz = Mineral.objects.create(name='Quartz', hardness=7) + GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) + ctype = ContentType.objects.get_for_model(quartz) + initial_data = [{ + 'tag': 'lizard', + 'content_type': ctype.pk, + 'object_id': quartz.pk, + }] + formset = GenericFormSet(initial=initial_data) + self.assertEqual(formset.forms[0].initial, initial_data[0]) + + def test_meta_widgets(self): + """TaggedItemForm has a widget defined in Meta.""" + Formset = generic_inlineformset_factory(TaggedItem, TaggedItemForm) + form = Formset().forms[0] + self.assertIsInstance(form['tag'].field.widget, CustomWidget) + + @isolate_apps('generic_relations') + def test_incorrect_content_type(self): + class BadModel(models.Model): + content_type = models.PositiveIntegerField() + + msg = "fk_name 'generic_relations.BadModel.content_type' is not a ForeignKey to ContentType" + with self.assertRaisesMessage(Exception, msg): + generic_inlineformset_factory(BadModel, TaggedItemForm) + + def test_save_new_uses_form_save(self): + class SaveTestForm(forms.ModelForm): + def save(self, *args, **kwargs): + self.instance.saved_by = 'custom method' + return super().save(*args, **kwargs) + + Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', form=SaveTestForm) + instance = ProxyRelatedModel.objects.create() + data = { + 'form-TOTAL_FORMS': '1', + 'form-INITIAL_FORMS': '0', + 'form-MAX_NUM_FORMS': '', + 'form-0-title': 'foo', + } + formset = Formset(data, instance=instance, prefix='form') + self.assertTrue(formset.is_valid()) + new_obj = formset.save()[0] + self.assertEqual(new_obj.saved_by, 'custom method') + + def test_save_new_for_proxy(self): + Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', for_concrete_model=False) + instance = ProxyRelatedModel.objects.create() + data = { + 'form-TOTAL_FORMS': '1', + 'form-INITIAL_FORMS': '0', + 'form-MAX_NUM_FORMS': '', + 'form-0-title': 'foo', + } + formset = Formset(data, instance=instance, prefix='form') + self.assertTrue(formset.is_valid()) + new_obj, = formset.save() + self.assertEqual(new_obj.obj, instance) + + def test_save_new_for_concrete(self): + Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', for_concrete_model=True) + instance = ProxyRelatedModel.objects.create() + data = { + 'form-TOTAL_FORMS': '1', + 'form-INITIAL_FORMS': '0', + 'form-MAX_NUM_FORMS': '', + 'form-0-title': 'foo', + } + formset = Formset(data, instance=instance, prefix='form') + self.assertTrue(formset.is_valid()) + new_obj, = formset.save() + self.assertNotIsInstance(new_obj.obj, ProxyRelatedModel) diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index d3aa3b15f8..4c27b6f3d5 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -1,11 +1,8 @@ -from django import forms -from django.contrib.contenttypes.forms import generic_inlineformset_factory from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldError -from django.db import IntegrityError, models +from django.db import IntegrityError from django.db.models import Q from django.test import SimpleTestCase, TestCase -from django.test.utils import isolate_apps from .models import ( AllowsNullGFK, Animal, Carrot, Comparison, ConcreteRelatedModel, @@ -422,73 +419,6 @@ class GenericRelationsTests(TestCase): granite.delete() # deleting the rock should delete the related tag. self.assertEqual(ValuableTaggedItem.objects.count(), 0) - def test_generic_inline_formsets(self): - GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) - formset = GenericFormSet() - self.assertHTMLEqual( - ''.join(form.as_p() for form in formset.forms), - """

-

- -

""" - ) - - formset = GenericFormSet(instance=Animal()) - self.assertHTMLEqual( - ''.join(form.as_p() for form in formset.forms), - """

-

-

""" - ) - - platypus = Animal.objects.create( - common_name="Platypus", latin_name="Ornithorhynchus anatinus" - ) - platypus.tags.create(tag="shiny") - GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) - formset = GenericFormSet(instance=platypus) - tagged_item_id = TaggedItem.objects.get( - tag='shiny', object_id=platypus.id - ).id - self.assertHTMLEqual( - ''.join(form.as_p() for form in formset.forms), - """

-

-

- -

-

-

-

- -

""" % tagged_item_id - ) - - lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo") - formset = GenericFormSet(instance=lion, prefix='x') - self.assertHTMLEqual( - ''.join(form.as_p() for form in formset.forms), - """

-

-

-

""" - ) - def test_gfk_manager(self): # GenericForeignKey should not use the default manager (which may filter objects) #16048 tailless = Gecko.objects.create(has_tail=False) @@ -513,22 +443,6 @@ id="id_generic_relations-taggeditem-content_type-object_id-1-id" />

""" % tag TaggedItem.objects.create(content_object=bear, tag='orange') self.assertEqual(Carrot.objects.get(tags__tag='orange'), bear) - def test_generic_inline_formsets_initial(self): - """ - Test for #17927 Initial values support for BaseGenericInlineFormSet. - """ - quartz = Mineral.objects.create(name="Quartz", hardness=7) - - GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) - ctype = ContentType.objects.get_for_model(quartz) - initial_data = [{ - 'tag': 'lizard', - 'content_type': ctype.pk, - 'object_id': quartz.pk, - }] - formset = GenericFormSet(initial=initial_data) - self.assertEqual(formset.forms[0].initial, initial_data[0]) - def test_get_or_create(self): # get_or_create should work with virtual fields (content_object) quartz = Mineral.objects.create(name="Quartz", hardness=7) @@ -586,98 +500,6 @@ id="id_generic_relations-taggeditem-content_type-object_id-1-id" />

""" % tag self.assertEqual(tag.content_object, spinach) -class CustomWidget(forms.TextInput): - pass - - -class TaggedItemForm(forms.ModelForm): - class Meta: - model = TaggedItem - fields = '__all__' - widgets = {'tag': CustomWidget} - - -class GenericInlineFormsetTest(TestCase): - def test_generic_inlineformset_factory(self): - """ - Regression for #14572: Using base forms with widgets - defined in Meta should not raise errors. - """ - Formset = generic_inlineformset_factory(TaggedItem, TaggedItemForm) - form = Formset().forms[0] - self.assertIsInstance(form['tag'].field.widget, CustomWidget) - - @isolate_apps('generic_relations') - def test_incorrect_content_type(self): - class BadModel(models.Model): - content_type = models.PositiveIntegerField() - - msg = "fk_name 'generic_relations.BadModel.content_type' is not a ForeignKey to ContentType" - with self.assertRaisesMessage(Exception, msg): - generic_inlineformset_factory(BadModel, TaggedItemForm) - - def test_save_new_uses_form_save(self): - """ - Regression for #16260: save_new should call form.save() - """ - class SaveTestForm(forms.ModelForm): - def save(self, *args, **kwargs): - self.instance.saved_by = "custom method" - return super().save(*args, **kwargs) - - Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', form=SaveTestForm) - - instance = ProxyRelatedModel.objects.create() - - data = { - 'form-TOTAL_FORMS': '1', - 'form-INITIAL_FORMS': '0', - 'form-MAX_NUM_FORMS': '', - 'form-0-title': 'foo', - } - - formset = Formset(data, instance=instance, prefix='form') - self.assertTrue(formset.is_valid()) - new_obj = formset.save()[0] - self.assertEqual(new_obj.saved_by, "custom method") - - def test_save_new_for_proxy(self): - Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', for_concrete_model=False) - - instance = ProxyRelatedModel.objects.create() - - data = { - 'form-TOTAL_FORMS': '1', - 'form-INITIAL_FORMS': '0', - 'form-MAX_NUM_FORMS': '', - 'form-0-title': 'foo', - } - - formset = Formset(data, instance=instance, prefix='form') - self.assertTrue(formset.is_valid()) - - new_obj, = formset.save() - self.assertEqual(new_obj.obj, instance) - - def test_save_new_for_concrete(self): - Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', for_concrete_model=True) - - instance = ProxyRelatedModel.objects.create() - - data = { - 'form-TOTAL_FORMS': '1', - 'form-INITIAL_FORMS': '0', - 'form-MAX_NUM_FORMS': '', - 'form-0-title': 'foo', - } - - formset = Formset(data, instance=instance, prefix='form') - self.assertTrue(formset.is_valid()) - - new_obj, = formset.save() - self.assertNotIsInstance(new_obj.obj, ProxyRelatedModel) - - class ProxyRelatedModelTest(TestCase): def test_default_behavior(self): """