Chooser examples

Introduction to Comboboxes

Examples in this document use the lino_book.projects.chooser demo project.

>>> from lino import startup
>>> startup('lino_book.projects.chooser.settings')
>>> from lino.api.doctest import *
>>> be = chooser.Country.objects.get(name="Belgium")
>>> fr = chooser.Country.objects.get(name="France")

You instantiate a chooser by specifying a model and a fieldname. The fieldname must be the name of a field that has been defined in your model. A chooser for a field FOO on a model will look whether the model defines a class method FOO_choices().

Choosers on ForeignKey fields

A Contact has ForeignKey fields to Country and City. In an entry form for a Contact you want only the cities of that country when selecting a city.

How to use a Chooser on a ForeignKey:

>>> from lino.core.utils import get_field
>>> city = chooser.Contact.get_chooser_for_field('city')
>>> [str(o) for o in city.get_choices(country=be)]
['Brussels', 'Eupen', 'Gent']
>>> [str(o) for o in city.get_choices(country=fr)]
['Bordeaux', 'Paris']
>>> [str(o) for o in city.get_choices()]
['Bordeaux', 'Brussels', 'Eupen', 'Gent', 'Narva', 'Paris', 'Tallinn', 'Tartu']

There is no method country_choices, so Contact.country has no Chooser:

>>> print(chooser.Contact.get_chooser_for_field('country'))
None

Char field choosers

How to make and use a chooser on a char-field, to limit the valid values:

from django.db import models
from lino.api import dd, _

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
)

MENU = [
    # name reserved_for
    ('Potato', None),
    ('Vegetable', 'SO JR SR GR'),
    ('Meat', 'JR SR GR'),
    ('Fish', 'SR GR'),
]

year_in_school = models.CharField(
        max_length=2, choices=YEAR_IN_SCHOOL_CHOICES, blank=True)
food = models.CharField(max_length=20, blank=True)

@dd.chooser(simple_values=True)
def food_choices(cls, year_in_school):
    food = []
    for name, reserved_for in MENU:
        if (year_in_school is None) or (reserved_for is None) or year_in_school in reserved_for:
            food.append(name)
    return food
>>> food = chooser.Contact.get_chooser_for_field('food')
>>> [str(o) for o in food.get_choices()]
['Potato', 'Vegetable', 'Meat', 'Fish']
>>> [str(o) for o in food.get_choices(year_in_school='FR')]
['Potato']
>>> [str(o) for o in food.get_choices(year_in_school='SO')]
['Potato', 'Vegetable']

Choosers that depend on current user

Sometimes you require the current user to determine the choices for a field. To do this include a "ar" parameter to your chooser method:

@dd.chooser()
def food_choices(cls, ar):
    year_in_school = ar.get_user().year_in_school if ar is not None else None
    food = []
    for name, reserved_for in MENU:
        if (year_in_school is None) or (reserved_for is None) or year_in_school in reserved_for:
            food.append(name)
    return food
>>> ses = rt.login("robin")
... 
>>> [str(o) for o in food.get_choices(ar=ses)]
... 
['Potato', 'Vegetable']

Not that this example doesn't work in our choices demo as there are no users. This tests assumes that the user model has a year_in_school field.

This use case would be required if users are submitting what food they want to eat during the week on a separate table.

Special cases

Note that Chooser.get_choices() ignores any unused keyword arguments:

>>> [str(o) for o in city.get_choices(country=be,foo=1,bar=True,baz='7')]
['Brussels', 'Eupen', 'Gent']

Examples of choosers on a ChoiceListField are