123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- 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),
- """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">
- Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text"
- name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50"></p>
- <p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label>
- <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE"
- id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">
- <input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id"
- id="id_generic_relations-taggeditem-content_type-object_id-0-id"></p>"""
- )
- formset = GenericFormSet(instance=Animal())
- self.assertHTMLEqual(
- ''.join(form.as_p() for form in formset.forms),
- """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">
- Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag"
- type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50"></p>
- <p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label>
- <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE"
- id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE"><input type="hidden"
- name="generic_relations-taggeditem-content_type-object_id-0-id"
- id="id_generic_relations-taggeditem-content_type-object_id-0-id"></p>"""
- )
- 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),
- """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label>
- <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text"
- name="generic_relations-taggeditem-content_type-object_id-0-tag" value="shiny" maxlength="50"></p>
- <p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label>
- <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE"
- id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">
- <input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id"
- value="%s" id="id_generic_relations-taggeditem-content_type-object_id-0-id"></p>
- <p><label for="id_generic_relations-taggeditem-content_type-object_id-1-tag">Tag:</label>
- <input id="id_generic_relations-taggeditem-content_type-object_id-1-tag" type="text"
- name="generic_relations-taggeditem-content_type-object_id-1-tag" maxlength="50"></p>
- <p><label for="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">Delete:</label>
- <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-1-DELETE"
- id="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">
- <input type="hidden" name="generic_relations-taggeditem-content_type-object_id-1-id"
- id="id_generic_relations-taggeditem-content_type-object_id-1-id"></p>""" % 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),
- """<p><label for="id_x-0-tag">Tag:</label>
- <input id="id_x-0-tag" type="text" name="x-0-tag" maxlength="50"></p>
- <p><label for="id_x-0-DELETE">Delete:</label> <input type="checkbox" name="x-0-DELETE" id="id_x-0-DELETE">
- <input type="hidden" name="x-0-id" id="id_x-0-id"></p>"""
- )
- 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(),
- '<input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" value="%s" '
- 'id="id_generic_relations-taggeditem-content_type-object_id-0-id">' % 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)
- def test_initial_count(self):
- GenericFormSet = generic_inlineformset_factory(TaggedItem)
- data = {
- 'form-TOTAL_FORMS': '3',
- 'form-INITIAL_FORMS': '3',
- 'form-MAX_NUM_FORMS': '',
- }
- formset = GenericFormSet(data=data, prefix='form')
- self.assertEqual(formset.initial_form_count(), 3)
- formset = GenericFormSet(data=data, prefix='form', save_as_new=True)
- self.assertEqual(formset.initial_form_count(), 0)
- def test_save_as_new(self):
- """
- The save_as_new parameter creates new items that are associated with
- the object.
- """
- lion = Animal.objects.create(common_name='Lion', latin_name='Panthera leo')
- yellow = lion.tags.create(tag='yellow')
- hairy = lion.tags.create(tag='hairy')
- GenericFormSet = generic_inlineformset_factory(TaggedItem)
- data = {
- 'form-TOTAL_FORMS': '3',
- 'form-INITIAL_FORMS': '2',
- 'form-MAX_NUM_FORMS': '',
- 'form-0-id': str(yellow.pk),
- 'form-0-tag': 'hunts',
- 'form-1-id': str(hairy.pk),
- 'form-1-tag': 'roars',
- }
- formset = GenericFormSet(data, instance=lion, prefix='form', save_as_new=True)
- self.assertTrue(formset.is_valid())
- tags = formset.save()
- self.assertEqual([tag.tag for tag in tags], ['hunts', 'roars'])
- hunts, roars = tags
- self.assertSequenceEqual(lion.tags.order_by('tag'), [hairy, hunts, roars, yellow])
- def test_absolute_max(self):
- GenericFormSet = generic_inlineformset_factory(TaggedItem, absolute_max=1500)
- data = {
- 'form-TOTAL_FORMS': '1501',
- 'form-INITIAL_FORMS': '0',
- 'form-MAX_NUM_FORMS': '0',
- }
- formset = GenericFormSet(data=data, prefix='form')
- self.assertIs(formset.is_valid(), False)
- self.assertEqual(len(formset.forms), 1500)
- self.assertEqual(
- formset.non_form_errors(),
- ['Please submit at most 1000 forms.'],
- )
- def test_absolute_max_with_max_num(self):
- GenericFormSet = generic_inlineformset_factory(
- TaggedItem,
- max_num=20,
- absolute_max=100,
- )
- data = {
- 'form-TOTAL_FORMS': '101',
- 'form-INITIAL_FORMS': '0',
- 'form-MAX_NUM_FORMS': '0',
- }
- formset = GenericFormSet(data=data, prefix='form')
- self.assertIs(formset.is_valid(), False)
- self.assertEqual(len(formset.forms), 100)
- self.assertEqual(
- formset.non_form_errors(),
- ['Please submit at most 20 forms.'],
- )
- def test_can_delete_extra(self):
- GenericFormSet = generic_inlineformset_factory(
- TaggedItem,
- can_delete=True,
- can_delete_extra=True,
- extra=2,
- )
- formset = GenericFormSet()
- self.assertEqual(len(formset), 2)
- self.assertIn('DELETE', formset.forms[0].fields)
- self.assertIn('DELETE', formset.forms[1].fields)
- def test_disable_delete_extra(self):
- GenericFormSet = generic_inlineformset_factory(
- TaggedItem,
- can_delete=True,
- can_delete_extra=False,
- extra=2,
- )
- formset = GenericFormSet()
- self.assertEqual(len(formset), 2)
- self.assertNotIn('DELETE', formset.forms[0].fields)
- self.assertNotIn('DELETE', formset.forms[1].fields)
|