Simplify dealing with (large) choices
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
choicer
.gitignore
.travis.yml
LICENSE
README.rst
setup.py

README.rst

django-choicer

https://travis-ci.org/tonimichel/django-choicer.svg?branch=master

Simplify dealing with (large) choices.

Getting started

Imagine we got a model called Subscription providing a field state.

models:

from django.db import models
import choicer

subscription_choicer = choicer.Choicer([
    dict(
        name='started',
        value=0,
        verbose_name='Approved'
    ),
    dict(
        name='inprogress',
        value=1,
        verbose_name='In progress'
    ),
    dict(
        name='completed',
        value=2,
        verbose_name='Completed'
    ),
    dict(
        name='approved',
        value=3,
        verbose_name='Approved'
    ),
    dict(
        name='dismissed',
        value=4,
        verbose_name='Dismissed'
    ),
    dict(
        name='wartinglist',
        value=5,
        verbose_name='On waiting list'
    ),
])

@subscription_choicer.apply(field_name='state')
class Subscription(models.Model):
    # some fields
    state = models.IntegerField(choices=sub_choicer.get_choices())

After we defined our model and applied our choicer, we now want to play with the api:

s = Subscription()
s.set_state_started()
s.save()

print(s.is_state_started())
# True

s.set_state_inprogress()
print(s.is_state_approved())
# False
print (s.is_state_started())
# True

choice = s.STATE_CHOICER.get_by_name('dismissed')
print(choice)
# {'name': 'dismissed', 'value': 4, verbose_name='Dismissed'}

choice = s.STATE_CHOICER.get_by_value(5)
print(choice)
# {'name': 'waitinglist', 'value': 5, verbose_name='On waiting list'}

s.set_state_waitinglist()
print(s.state)
# 5
print(s.get_state())
# {'name': 'waitinglist', 'value': 5, verbose_name='On waiting list'}


s.STATE_CHOICER.get_choices()
# returns the choices

s.STATE_CHOICER.get_dict()
s.STATE_CHOICER.get_list()

Installation

code:

pip install git+https://github.com/tonimichel/django-choicer.git

As django-choicer neither provides models, nor templates, nor static files we dont neet to add it to our project's INSTALLED_APPS.

Motivation

Sometimes models need to provide a large set of choices. This may bring the following issues to deal with:

  • Querying

Actually we dont want to query our model by integer or string values which are not human-readable. So, instead of doing

MyModel.objects.filter(type=0)

its better to do something like this

MyModel.objects.filter(state=STATES.approved)

Furthermore it is sometimes necessary to provide instance methods that check for a certain model state. So instead of doing

if obj.state == 0:
    # do something

or a little better

if obj.state == STATES.approved

we actually want to do

if obj.is_state_approved():
    pass

which is the way to go as our model provide an explicit api check for a given state. Considering assignment of a choice, we got similar issues:

obj.state = 0

is worse than

obj.state = STATES.approved

But what we actually want to do is

obj.set_state_approved()

So, now imagine the following scenario. We got 8 different choices, so the naive way of checkin against the integers or strings defined in our choices is inacceptable. But also the way of constructing a "STATE" class for doing enum-like checks (obj.state == STATES.approved) is no that cool, as we actually want to do obj.is_state_approved. But, it would also be totally unacceptable to write 8 getters and 8 setters each providing the same code, especially when we need to change the naming of a choice during early development, which actually happend quite often after Phil Karlton's "There are only two hard things in Computer Science: cache invalidation and naming things".