summaryrefslogtreecommitdiff
path: root/tests/model_forms/tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/model_forms/tests.py')
-rw-r--r--tests/model_forms/tests.py260
1 files changed, 2 insertions, 258 deletions
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index 9b991d209d..fced7403ba 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -12,10 +12,9 @@ from django.core.validators import ValidationError
from django.db import connection, models
from django.db.models.query import EmptyQuerySet
from django.forms.models import (
- ModelChoiceIterator, ModelFormMetaclass, construct_instance,
- fields_for_model, model_to_dict, modelform_factory,
+ ModelFormMetaclass, construct_instance, fields_for_model, model_to_dict,
+ modelform_factory,
)
-from django.forms.widgets import CheckboxSelectMultiple
from django.template import Context, Template
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
@@ -1557,261 +1556,6 @@ class ModelFormBasicTests(TestCase):
obj.full_clean()
-class ModelChoiceFieldTests(TestCase):
- def setUp(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", slug="third-test", url="third")
-
- # ModelChoiceField ############################################################
- def test_modelchoicefield(self):
- f = forms.ModelChoiceField(Category.objects.all())
- 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('')
- with self.assertRaises(ValidationError):
- f.clean(None)
- with self.assertRaises(ValidationError):
- f.clean(0)
-
- # Invalid types that require TypeError to be caught (#22808).
- with self.assertRaises(ValidationError):
- f.clean([['fail']])
- with self.assertRaises(ValidationError):
- f.clean([{'foo': 'bar'}])
-
- self.assertEqual(f.clean(self.c2.id).name, "It's a test")
- self.assertEqual(f.clean(self.c3.id).name, 'Third')
-
- # Add a Category object *after* the ModelChoiceField has already been
- # instantiated. This proves clean() checks the database during clean() rather
- # than caching it at time of instantiation.
- c4 = Category.objects.create(name='Fourth', url='4th')
- self.assertEqual(f.clean(c4.id).name, 'Fourth')
-
- # Delete a Category object *after* the ModelChoiceField has already been
- # instantiated. This proves clean() checks the database during clean() rather
- # than caching it at time of instantiation.
- Category.objects.get(url='4th').delete()
- msg = "['Select a valid choice. That choice is not one of the available choices.']"
- with self.assertRaisesMessage(ValidationError, msg):
- f.clean(c4.id)
-
- def test_modelchoicefield_choices(self):
- f = forms.ModelChoiceField(Category.objects.filter(pk=self.c1.id), required=False)
- self.assertIsNone(f.clean(''))
- self.assertEqual(f.clean(str(self.c1.id)).name, "Entertainment")
- with self.assertRaises(ValidationError):
- f.clean('100')
-
- # len can be called on choices
- self.assertEqual(len(f.choices), 2)
-
- # 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")])
- self.assertEqual(f.clean(self.c2.id).name, "It's a test")
- with self.assertRaises(ValidationError):
- f.clean(self.c3.id)
-
- # check that we can safely iterate choices repeatedly
- gen_one = list(f.choices)
- gen_two = f.choices
- self.assertEqual(gen_one[2], (self.c2.pk, "It's a test"))
- self.assertEqual(list(gen_two), [
- ('', '---------'),
- (self.c1.pk, 'Entertainment'),
- (self.c2.pk, "It's a test")])
-
- # check that we can override the label_from_instance method to print custom labels (#4620)
- f.queryset = Category.objects.all()
- f.label_from_instance = lambda obj: "category " + str(obj)
- self.assertEqual(list(f.choices), [
- ('', '---------'),
- (self.c1.pk, 'category Entertainment'),
- (self.c2.pk, "category It's a test"),
- (self.c3.pk, 'category Third')])
-
- def test_modelchoicefield_11183(self):
- """
- Regression test for ticket #11183.
- """
- class ModelChoiceForm(forms.Form):
- category = forms.ModelChoiceField(Category.objects.all())
-
- form1 = ModelChoiceForm()
- field1 = form1.fields['category']
- # To allow the widget to change the queryset of field1.widget.choices correctly,
- # without affecting other forms, the following must hold:
- self.assertIsNot(field1, ModelChoiceForm.base_fields['category'])
- self.assertIs(field1.widget.choices.field, field1)
-
- def test_modelchoicefield_result_cache_not_shared(self):
- class ModelChoiceForm(forms.Form):
- category = forms.ModelChoiceField(Category.objects.all())
-
- form1 = ModelChoiceForm()
- self.assertCountEqual(form1.fields['category'].queryset, [self.c1, self.c2, self.c3])
- form2 = ModelChoiceForm()
- self.assertIsNone(form2.fields['category'].queryset._result_cache)
-
- def test_modelchoicefield_queryset_none(self):
- class ModelChoiceForm(forms.Form):
- category = forms.ModelChoiceField(queryset=None)
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.fields['category'].queryset = Category.objects.filter(slug__contains='test')
-
- form = ModelChoiceForm()
- self.assertCountEqual(form.fields['category'].queryset, [self.c2, self.c3])
-
- def test_modelchoicefield_22745(self):
- """
- #22745 -- Make sure that ModelChoiceField with RadioSelect widget
- doesn't produce unnecessary db queries when accessing its BoundField's
- attrs.
- """
- class ModelChoiceForm(forms.Form):
- category = forms.ModelChoiceField(Category.objects.all(), widget=forms.RadioSelect)
-
- form = ModelChoiceForm()
- field = form['category'] # BoundField
- template = Template('{{ field.name }}{{ field }}{{ field.help_text }}')
- with self.assertNumQueries(1):
- template.render(Context({'field': field}))
-
- def test_disabled_modelchoicefield(self):
- class ModelChoiceForm(forms.ModelForm):
- author = forms.ModelChoiceField(Author.objects.all(), disabled=True)
-
- class Meta:
- model = Book
- fields = ['author']
-
- book = Book.objects.create(author=Writer.objects.create(name='Test writer'))
- form = ModelChoiceForm({}, instance=book)
- self.assertEqual(
- form.errors['author'],
- ['Select a valid choice. That choice is not one of the available choices.']
- )
-
- def test_disabled_modelchoicefield_has_changed(self):
- field = forms.ModelChoiceField(Author.objects.all(), disabled=True)
- self.assertIs(field.has_changed('x', 'y'), False)
-
- def test_disabled_multiplemodelchoicefield(self):
- class ArticleForm(forms.ModelForm):
- categories = forms.ModelMultipleChoiceField(Category.objects.all(), required=False)
-
- class Meta:
- model = Article
- fields = ['categories']
-
- category1 = Category.objects.create(name='cat1')
- category2 = Category.objects.create(name='cat2')
- article = Article.objects.create(
- pub_date=datetime.date(1988, 1, 4),
- writer=Writer.objects.create(name='Test writer'),
- )
- article.categories.set([category1.pk])
-
- form = ArticleForm(data={'categories': [category2.pk]}, instance=article)
- self.assertEqual(form.errors, {})
- self.assertEqual([x.pk for x in form.cleaned_data['categories']], [category2.pk])
- # Disabled fields use the value from `instance` rather than `data`.
- form = ArticleForm(data={'categories': [category2.pk]}, instance=article)
- form.fields['categories'].disabled = True
- self.assertEqual(form.errors, {})
- self.assertEqual([x.pk for x in form.cleaned_data['categories']], [category1.pk])
-
- def test_disabled_modelmultiplechoicefield_has_changed(self):
- field = forms.ModelMultipleChoiceField(Author.objects.all(), disabled=True)
- self.assertIs(field.has_changed('x', 'y'), False)
-
- def test_modelchoicefield_iterator(self):
- """
- Iterator defaults to ModelChoiceIterator and can be overridden with
- the iterator attribute on a ModelChoiceField subclass.
- """
- field = forms.ModelChoiceField(Category.objects.all())
- self.assertIsInstance(field.choices, ModelChoiceIterator)
-
- class CustomModelChoiceIterator(ModelChoiceIterator):
- pass
-
- class CustomModelChoiceField(forms.ModelChoiceField):
- iterator = CustomModelChoiceIterator
-
- field = CustomModelChoiceField(Category.objects.all())
- self.assertIsInstance(field.choices, CustomModelChoiceIterator)
-
- def test_modelchoicefield_iterator_pass_model_to_widget(self):
- class CustomModelChoiceValue:
- def __init__(self, value, obj):
- self.value = value
- self.obj = obj
-
- def __str__(self):
- return str(self.value)
-
- class CustomModelChoiceIterator(ModelChoiceIterator):
- def choice(self, obj):
- value, label = super().choice(obj)
- return CustomModelChoiceValue(value, obj), label
-
- class CustomCheckboxSelectMultiple(CheckboxSelectMultiple):
- def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
- option = super().create_option(name, value, label, selected, index, subindex=None, attrs=None)
- # Modify the HTML based on the object being rendered.
- c = value.obj
- option['attrs']['data-slug'] = c.slug
- return option
-
- class CustomModelMultipleChoiceField(forms.ModelMultipleChoiceField):
- iterator = CustomModelChoiceIterator
- widget = CustomCheckboxSelectMultiple
-
- field = CustomModelMultipleChoiceField(Category.objects.all())
- self.assertHTMLEqual(
- field.widget.render('name', []),
- '''<ul>
-<li><label><input type="checkbox" name="name" value="%d" data-slug="entertainment">Entertainment</label></li>
-<li><label><input type="checkbox" name="name" value="%d" data-slug="its-test">It&#39;s a test</label></li>
-<li><label><input type="checkbox" name="name" value="%d" data-slug="third-test">Third</label></li>
-</ul>''' % (self.c1.pk, self.c2.pk, self.c3.pk),
- )
-
- def test_modelchoicefield_num_queries(self):
- """
- Widgets that render multiple subwidgets shouldn't make more than one
- database query.
- """
- categories = Category.objects.all()
-
- class CategoriesForm(forms.Form):
- radio = forms.ModelChoiceField(queryset=categories, widget=forms.RadioSelect)
- checkbox = forms.ModelMultipleChoiceField(queryset=categories, widget=forms.CheckboxSelectMultiple)
-
- template = Template("""
- {% for widget in form.checkbox %}{{ widget }}{% endfor %}
- {% for widget in form.radio %}{{ widget }}{% endfor %}
- """)
-
- with self.assertNumQueries(2):
- template.render(Context({'form': CategoriesForm()}))
-
-
class ModelMultipleChoiceFieldTests(TestCase):
def setUp(self):
self.c1 = Category.objects.create(