From bb5c7e4e8d783bf3a2880ab5cf1fa57fd35cd198 Mon Sep 17 00:00:00 2001 From: Mike Fogel Date: Fri, 11 Apr 2014 23:58:56 -0400 Subject: [PATCH] [1.7.x] Fixed #22537 -- Add tests and improved docs for field subclass with choices. Backport of 7fd1b35ed7 from master --- docs/ref/models/fields.txt | 4 ++-- tests/field_subclassing/fields.py | 5 +++++ tests/field_subclassing/models.py | 12 +++++++++++- tests/field_subclassing/tests.py | 14 ++++++++++++-- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 3a43d51560b..ed53b49e860 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -83,8 +83,8 @@ two items (e.g. ``[(A, B), (A, B) ...]``) to use as choices for this field. If this is given, the default form widget will be a select box with these choices instead of the standard text field. -The first element in each tuple is the actual value to be stored, and the -second element is the human-readable name. For example:: +The first element in each tuple is the actual value to be set on the model, +and the second element is the human-readable name. For example:: YEAR_IN_SCHOOL_CHOICES = ( ('FR', 'Freshman'), diff --git a/tests/field_subclassing/fields.py b/tests/field_subclassing/fields.py index d96ce8d873b..c2158824dfb 100644 --- a/tests/field_subclassing/fields.py +++ b/tests/field_subclassing/fields.py @@ -20,6 +20,11 @@ class Small(object): def __str__(self): return '%s%s' % (force_text(self.first), force_text(self.second)) + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.first == other.first and self.second == other.second + return False + class SmallField(six.with_metaclass(models.SubfieldBase, models.Field)): """ diff --git a/tests/field_subclassing/models.py b/tests/field_subclassing/models.py index c2f7e4f66b7..3ed465cd7fe 100644 --- a/tests/field_subclassing/models.py +++ b/tests/field_subclassing/models.py @@ -5,7 +5,7 @@ Tests for field subclassing. from django.db import models from django.utils.encoding import force_text -from .fields import SmallField, SmallerField, JSONField +from .fields import Small, SmallField, SmallerField, JSONField from django.utils.encoding import python_2_unicode_compatible @@ -22,5 +22,15 @@ class OtherModel(models.Model): data = SmallerField() +class ChoicesModel(models.Model): + SMALL_AB = Small('a', 'b') + SMALL_CD = Small('c', 'd') + SMALL_CHOICES = ( + (SMALL_AB, str(SMALL_AB)), + (SMALL_CD, str(SMALL_CD)), + ) + data = SmallField('small field', choices=SMALL_CHOICES) + + class DataModel(models.Model): data = JSONField() diff --git a/tests/field_subclassing/tests.py b/tests/field_subclassing/tests.py index 5f1dbac8a3b..5c695a455c2 100644 --- a/tests/field_subclassing/tests.py +++ b/tests/field_subclassing/tests.py @@ -2,12 +2,12 @@ from __future__ import unicode_literals import inspect -from django.core import serializers +from django.core import exceptions, serializers from django.db import connection from django.test import TestCase from .fields import Small, CustomTypedField -from .models import DataModel, MyModel, OtherModel +from .models import ChoicesModel, DataModel, MyModel, OtherModel class CustomField(TestCase): @@ -106,6 +106,16 @@ class CustomField(TestCase): self.assertIn('__module__', data) self.assertEqual(data['__module__'], 'field_subclassing.models') + def test_validation_of_choices_for_custom_field(self): + # a valid choice + o = ChoicesModel.objects.create(data=Small('a', 'b')) + o.full_clean() + + # an invalid choice + o = ChoicesModel.objects.create(data=Small('d', 'e')) + with self.assertRaises(exceptions.ValidationError): + o.full_clean() + class TestDbType(TestCase):