Metadata-Version: 1.1
Name: django-extended-choices
Version: 1.0.6.dev1
Summary: Little helper application to improve django choices(for fields)
Home-page: https://github.com/twidi/django-extended-choices
Author: Stephane "Twidi" Angel
Author-email: s.angel@twidi.com
License: BSD
Description: |PyPI Version| |Build Status| |Doc Status|
        
        django-extended-choices
        =======================
        
        A little application to improve Django choices
        ----------------------------------------------
        
        ``django-extended-choices`` aims to provide a better and more readable
        way of using choices_ in Django_.
        
        Installation
        ------------
        
        You can install directly via pip (since version ``0.3``)::
        
            $ pip install django-extended-choices
        
        Or from the Github_ repository (``master`` branch by default)::
        
            $ git clone git://github.com/twidi/django-extended-choices.git
            $ cd django-extended-choices
            $ sudo python setup.py install
        
        Usage
        -----
        
        The aim is to replace this:
        
        .. code-block:: python
        
            STATE_ONLINE  = 1
            STATE_DRAFT   = 2
            STATE_OFFLINE = 3
        
            STATE_CHOICES = (
                (STATE_ONLINE,  'Online'),
                (STATE_DRAFT,   'Draft'),
                (STATE_OFFLINE, 'Offline'),
            )
        
            STATE_DICT = dict(STATE_CHOICES)
        
            class Content(models.Model):
                title      = models.CharField(max_length=255)
                content    = models.TextField()
                state      = models.PositiveSmallIntegerField(choices=STATE_CHOICES, default=STATE_DRAFT)
        
                def __unicode__(self):
                    return u'Content "%s" (state=%s)' % (self.title, STATE_DICT[self.state])
        
            print(Content.objects.filter(state=STATE_ONLINE))
        
        by this:
        
        .. code-block:: python
        
            from extended_choices import Choices
        
            STATES = Choices(
                ('ONLINE',  1, 'Online'),
                ('DRAFT',   2, 'Draft'),
                ('OFFLINE', 3, 'Offline'),
            )
        
            class Content(models.Model):
                title      = models.CharField(max_length=255)
                content    = models.TextField()
                state      = models.PositiveSmallIntegerField(choices=STATES, default=STATES.DRAFT)
        
                def __unicode__(self):
                    return u'Content "%s" (state=%s)' % (self.title, STATES.for_value(self.state).display)
        
            print(Content.objects.filter(state=STATES.ONLINE))
        
        
        As you can see there is only one declaration for all states with, for each state, in order:
        
        * the pseudo-constant name which can be used (``STATES.ONLINE`` replaces the previous ``STATE_ONLINE``)
        * the value to use in the database - which could equally be a string
        * the name to be displayed - and you can wrap the text in ``ugettext_lazy()`` if you need i18n
        
        And then, you can use:
        
        * ``STATES``, or ``STATES.choices``, to use with ``choices=`` in fields declarations
        * ``STATES.for_constant(constant)``, to get the choice entry from the constant name
        * ``STATES.for_value(constant)``, to get the choice entry from the key used in database
        * ``STATES.for_display(constant)``, to get the choice entry from the displayable value (can be useful in some case)
        
        Each choice entry obtained by ``for_constant``, ``for_value`` and ``for_display`` return a tuple as
        given to the ``Choices`` constructor, but with additional attributes:
        
        .. code-block:: python
        
            >>> entry = STATES.for_constant('ONLINE')
            >>> entry == ('ONLINE', 1, 'Online')
            True
            >>> entry.constant
            'ONLINE'
            >>> entry.value
            1
            >>> entry.display
            'Online'
        
        These attributes are chainable (with a weird example to see chainability):
        
        .. code-block:: python
        
            >>> entry.constant.value
            1
            >>> entry.constant.value.value.display.constant.display
            'Online'
        
        To allow this, we had to remove support for ``None`` values. Use empty strings instead.
        
        Note that constants can be accessed via a dict key (``STATES['ONLINE']`` for example) if
        you want to fight your IDE that may warn you about undefined attributes.
        
        
        You can check whether a value is in a ``Choices`` object directly:
        
        .. code-block:: python
        
            >>> 1 in STATES
            True
            >>> 42 in STATES
            False
        
        
        You can even iterate on a ``Choices`` objects to get choices as seen by Django:
        
        .. code-block:: python
        
            >>> for choice in STATES:
            ...     print(choice)
            (1, 'Online')
            (2, 'Draf')
            (3, 'Offline')
        
        To get all choice entries as given to the ``Choices`` object, you can use the ``entries``
        attribute:
        
        .. code-block:: python
        
            >>> for choice_entry in STATES.entries:
            ...     print(choice_entry)
            ('ONLINE',  1, 'Online'),
            ('DRAFT',   2, 'Draft'),
            ('OFFLINE', 3, 'Offline'),
        
        Or the following dicts, using constants, values or display names, as keys, and the matching
        choice entry as values:
        
        * ``STATES.constants``
        * ``STATES.values``
        * ``STATES.displays``
        
        
        .. code-block:: python
        
            >>> STATES.constants['ONLINE'] is STATES.for_constant('ONLINE')
            True
            >>> STATES.values[2] is STATES.for_value(2)
            True
            >>> STATES.displays['Offline'] is STATES.for_display('Offline')
            True
        
        If you want these dicts to be ordered, you can pass the dict class to use to the
        ``Choices`` constructor:
        
        .. code-block:: python
        
            from collections import OrderedDict
            STATES = Choices(
                ('ONLINE',  1, 'Online'),
                ('DRAFT',   2, 'Draft'),
                ('OFFLINE', 3, 'Offline'),
                dict_class = OrderedDict
            )
        
        You can check if a constant, value, or display name exists:
        
        .. code-block:: python
        
            >>> STATES.has_constant('ONLINE')
            True
            >>> STATES.has_value(1)
            True
            >>> STATES.has_display('Online')
            True
        
        You can create subsets of choices within the same ``Choices`` instance:
        
        .. code-block:: python
        
            >>> STATES.add_subset('NOT_ONLINE', ('DRAFT', 'OFFLINE',))
            >>> STATES.NOT_ONLINE
            (2, 'Draft')
            (3, 'Offline')
        
        Now, ``STATES.NOT_ONLINE`` is a real ``Choices`` instance, with a subset of the main ``STATES``
        constants.
        
        You can use it to generate choices for when you only want a subset of choices available:
        
        .. code-block:: python
        
            offline_state = models.PositiveSmallIntegerField(
                choices=STATES.NOT_ONLINE,
                default=STATES.DRAFT
            )
        
        As the subset is a real ``Choices`` instance, you have the same attributes and methods:
        
        .. code-block:: python
        
            >>> STATES.NOT_ONLINE.for_constant('OFFLINE').value
            3
            >>> STATES.NOT_ONLINE.for_value(1).constant
            Traceback (most recent call last):
            ...
            KeyError: 3
            >>> list(STATES.NOT_ONLINE.constants.keys())
            ['DRAFT', 'OFFLINE]
            >>> STATES.NOT_ONLINE.has_display('Online')
            False
        
        You can create as many subsets as you want, reusing the same constants if needed:
        
        .. code-block:: python
        
            STATES.add_subset('NOT_OFFLINE', ('ONLINE', 'DRAFT'))
        
        If you want to check membership in a subset you could do:
        
        .. code-block:: python
        
            def is_online(self):
                # it's an example, we could have just tested with STATES.ONLINE
                return self.state not in STATES.NOT_ONLINE_DICT
        
        You can add choice entries in many steps using ``add_choices``, possibly creating subsets at
        the same time.
        
        To construct the same ``Choices`` as before, we could have done:
        
        .. code-block:: python
        
            STATES = Choices()
            STATES.add_choices(
                ('ONLINE', 1, 'Online)
            )
            STATES.add_choices(
                ('DRAFT',   2, 'Draft'),
                ('OFFLINE', 3, 'Offline'),
                name='NOT_ONLINE'
            )
        
        You can also pass the ``argument`` to the ``Choices`` constructor to create a subset with all
        the choices entries added at the same time (it will call ``add_choices`` with the name and the
        entries)
        
        The list of existing subset names is in the ``subsets`` attributes of the parent ``Choicess`` object.
        
        Notes
        -----
        
        * You also have a very basic field (``NamedExtendedChoiceFormField```) in ``extended_choices.fields`` which accept constant names instead of values
        * Feel free to read the source to learn more about this little Django app.
        * You can declare your choices where you want. My usage is in the ``models.py`` file, just before the class declaration.
        
        Compatibility
        -------------
        
        The version ``1.0`` provides a totally new API, but stays fully compatible with the previous one
        (``0.4.1``). So it adds a lot of attributes in each ``Choices`` instance:
        
        * ``CHOICES``
        * ``CHOICES_DICT``
        * ``REVERTED_CHOICES_DICT``
        * ``CHOICES_CONST_DICT``
        
        (And 4 more for each subset)
        
        If you don't want it, simply set the argument ``retro_compatibility`` to ``False`` when creating
        a ``Choices`` instance:
        
        .. code-block:: python
        
            STATES = Choices(
                ('ONLINE',  1, 'Online'),
                ('DRAFT',   2, 'Draft'),
                ('OFFLINE', 3, 'Offline'),
                retro_compatibility=False
            )
        
        This flag is currently ``True`` by default, and it will not be changed for at least 6 months
        counting from the publication of this version ``1.0`` (``1st of May, 2015``, so until the
        ``1st of November, 2015``, AT LEAST, the compatibility will be on by default).
        
        Then, the flag will stay but will be off by default. To keep compatibility, you'll have to
        pass the ``retro_compatibility`` argument and set it to ``True``.
        
        Then, after another period of 6 months minimum, the flag and all the retro_compatibility code
        will be removed (so not before ``1st of May, 2016``).
        
        Note that you can use a specific version by pinning it in your requirements.
        
        The only exception to these rules, it's the support of Django ``1.4`` that was removed in version
        ``1.0.3`` due to some incompatibility problems with ``ugettext_lazy``.
        
        Also, the support of ``None`` values was removed, raising a ``ValueError`` telling the user to
        instead use an empty string.
        
        
        License
        -------
        
        Available under the BSD_ License. See the ``LICENSE`` file included
        
        Python 3?
        ---------
        
        Of course! We support python ``2.6``, ``2.7``, ``3.3`` and `3.4`, for Django version ``1.5.x`` to
        ``1.8.x``, respecting the `Django matrix`_ (except for python ``2.5`` and ``3.2`` which are not
        supported by ``django-extended-choices``)
        
        
        Tests
        -----
        
        To run tests from the code source, create a virtualenv or activate one, install Django, then::
        
            python -m extended_choices.tests
        
        
        We also provides some quick doctests in the code documentation. To execute them::
        
            python -m extended_choices.choices
        
        
        Source code
        -----------
        
        The source code is available on Github_.
        
        
        Developing
        ----------
        
        If you want to participate in the development of this library, you'll need ``Django``
        installed in your virtualenv. If you don't have it, simply run::
        
            pip install -r requirements-dev.txt
        
        Don't forget to run the tests ;)
        
        Feel free to propose a pull request on Github_!
        
        A few minutes after your pull request, tests will be executed on TravisCi_ for all the versions
        of python and Django we support.
        
        
        Documentation
        -------------
        
        You can find the documentation on ReadTheDoc_
        
        To update the documentation, you'll need some tools::
        
            pip install -r requirements-makedoc.txt
        
        Then go to the ``docs`` directory, and run::
        
            make html
        
        Author
        ------
        Written by Stephane "Twidi" Angel <s.angel@twidi.com> (http://twidi.com), originally for http://www.liberation.fr
        
        .. _choices: http://docs.djangoproject.com/en/1.5/ref/models/fields/#choices
        .. _Django: http://www.djangoproject.com/
        .. _Github: https://github.com/twidi/django-extended-choices
        .. _Django matrix: https://docs.djangoproject.com/en/1.8/faq/install/#what-python-version-can-i-use-with-django
        .. _TravisCi: https://travis-ci.org/twidi/django-extended-choices/pull_requests
        .. _ReadTheDoc: http://django-extended-choices.readthedocs.org
        .. _BSD: http://opensource.org/licenses/BSD-3-Clause
        
        .. |PyPI Version| image:: https://img.shields.io/pypi/v/django-extended-choices.png
           :target: https://pypi.python.org/pypi/django-extended-choices
           :alt: PyPI Version
        .. |Build Status| image:: https://travis-ci.org/twidi/django-extended-choices.png
           :target: https://travis-ci.org/twidi/django-extended-choices
           :alt: Build Status on Travis CI
        .. |Doc Status| image:: https://readthedocs.org/projects/django-extended-choices/badge/?version=latest
           :target: http://django-extended-choices.readthedocs.org
           :alt: Documentation Status on ReadTheDoc
        
        .. image:: https://d2weczhvl823v0.cloudfront.net/twidi/django-extended-choices/trend.png
           :alt: Bitdeli badge
           :target: https://bitdeli.com/free
        
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Django
Classifier: Framework :: Django :: 1.4
Classifier: Framework :: Django :: 1.5
Classifier: Framework :: Django :: 1.6
Classifier: Framework :: Django :: 1.7
Classifier: Framework :: Django :: 1.8
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
