From 452ac5cd21d25cae0e1fd596e4303d819d516d03 Mon Sep 17 00:00:00 2001 From: Alejandro Varas Date: Thu, 14 Nov 2013 16:12:31 -0300 Subject: [PATCH 1/2] Added `choices_name` parameter to StatusField --- docs/fields.rst | 19 ++++++++++++++++--- model_utils/fields.py | 13 ++++++++----- model_utils/tests/models.py | 5 +++++ model_utils/tests/tests.py | 5 ++++- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/fields.rst b/docs/fields.rst index 5da4ab4..02ca6ef 100644 --- a/docs/fields.rst +++ b/docs/fields.rst @@ -8,9 +8,10 @@ StatusField A simple convenience for giving a model a set of "states." ``StatusField`` is a ``CharField`` subclass that expects to find a -``STATUS`` class attribute on its model, and uses that as its -``choices``. Also sets a default ``max_length`` of 100, and sets its -default value to the first item in the ``STATUS`` choices: +class attribute called ``STATUS`` on its model or you can pass +``choices_name`` to use a different attribute name, and uses that as +its ``choices``. Also sets a default ``max_length`` of 100, and sets +its default value to the first item in the ``STATUS`` choices: .. code-block:: python @@ -25,6 +26,18 @@ default value to the first item in the ``STATUS`` choices: (The ``STATUS`` class attribute does not have to be a :ref:`Choices` instance, it can be an ordinary list of two-tuples). +Using a different name for the model's choices class attribute + +.. code-block:: python + + from model_utils.fields import StatusField + from model_utils import Choices + + class Article(models.Model): + ANOTHER_CHOICES = Choices('draft', 'published') + # ... + another_field = StatusField(choices_name='ANOTHER_CHOICES') + ``StatusField`` does not set ``db_index=True`` automatically; if you expect to frequently filter on your status field (and it will have enough selectivity to make an index worthwhile) you may want to add this diff --git a/model_utils/fields.py b/model_utils/fields.py index 83e9e9a..4daa30a 100644 --- a/model_utils/fields.py +++ b/model_utils/fields.py @@ -5,6 +5,8 @@ from django.conf import settings from django.utils.encoding import python_2_unicode_compatible from django.utils.timezone import now +DEFAULT_CHOICES_NAME = 'STATUS' + class AutoCreatedField(models.DateTimeField): """ @@ -48,16 +50,17 @@ class StatusField(models.CharField): def __init__(self, *args, **kwargs): kwargs.setdefault('max_length', 100) self.check_for_status = not kwargs.pop('no_check_for_status', False) + self.choices_name = kwargs.pop('choices_name', DEFAULT_CHOICES_NAME) super(StatusField, self).__init__(*args, **kwargs) def prepare_class(self, sender, **kwargs): if not sender._meta.abstract and self.check_for_status: - assert hasattr(sender, 'STATUS'), \ - "To use StatusField, the model '%s' must have a STATUS choices class attribute." \ - % sender.__name__ - self._choices = sender.STATUS + assert hasattr(sender, self.choices_name), \ + "To use StatusField, the model '%s' must have a %s choices class attribute." \ + % (sender.__name__, self.choices_name) + self._choices = getattr(sender, self.choices_name) if not self.has_default(): - self.default = tuple(sender.STATUS)[0][0] # set first as default + self.default = tuple(getattr(sender, self.choices_name))[0][0] # set first as default def contribute_to_class(self, cls, name): models.signals.class_prepared.connect(self.prepare_class, sender=cls) diff --git a/model_utils/tests/models.py b/model_utils/tests/models.py index 5d13f46..9dd4364 100644 --- a/model_utils/tests/models.py +++ b/model_utils/tests/models.py @@ -352,3 +352,8 @@ class StatusFieldDefaultFilled(models.Model): class StatusFieldDefaultNotFilled(models.Model): STATUS = Choices((0, "no", "No"), (1, "yes", "Yes")) status = StatusField() + + +class StatusFieldChoicesName(models.Model): + NAMED_STATUS = Choices((0, "no", "No"), (1, "yes", "Yes")) + status = StatusField(choices_name='NAMED_STATUS') diff --git a/model_utils/tests/tests.py b/model_utils/tests/tests.py index 5cb0413..4553ed4 100644 --- a/model_utils/tests/tests.py +++ b/model_utils/tests/tests.py @@ -28,7 +28,7 @@ from model_utils.tests.models import ( ModelTracked, ModelTrackedFK, ModelTrackedNotDefault, ModelTrackedMultiple, InheritedModelTracked, Tracked, TrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple, InheritedTracked, StatusFieldDefaultFilled, StatusFieldDefaultNotFilled, - InheritanceManagerTestChild3) + InheritanceManagerTestChild3, StatusFieldChoicesName) class GetExcerptTests(TestCase): @@ -259,6 +259,9 @@ class StatusFieldTests(TestCase): instance = StatusFieldDefaultFilled() self.assertEqual(instance.get_status_display(), "Yes") + def test_choices_name(self): + StatusFieldChoicesName() + class ChoicesTests(TestCase): def setUp(self): From ae13fe2f41faa07dbdb2597be7c74a1846db323b Mon Sep 17 00:00:00 2001 From: Alejandro Varas Date: Thu, 14 Nov 2013 16:39:19 -0300 Subject: [PATCH 2/2] Updated `CHANGES.rst` --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 359532e..74eb663 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,9 @@ CHANGES master (unreleased) ------------------- +* Can pass `choices_name` to `StatusField` to use a different name for + choices class attribute. ``STATUS`` is used by default. + * Can pass model subclasses, rather than strings, into `select_subclasses()`. Thanks Keryn Knight. Merge of GH-79.