Usage¶
Define lookups in a lookups.py module in your app, which izaya imports on startup:
from izaya import ModelLookup, register
@register
class ArcLookup(ModelLookup):
model = Arc
search_fields = ["name__unaccent__icontains"]
search_fields holds complete field lookups on text fields, and a record matches if any of them
do. Each lookup receives the search text as is, so a numeric lookup such as pk__exact fails on
anything but a number. Override search to handle those. Use the lookup in a form, with
multiple=True for a multi-select:
from izaya import LookupWidget
class IssueForm(forms.ModelForm):
class Meta:
model = Issue
fields = ["arcs"]
widgets = {"arcs": LookupWidget(ArcLookup, multiple=True)}
Customizing a lookup¶
Attribute or method |
Purpose |
|---|---|
|
Search behaviour, defaulting to |
|
Messages shown in the results |
|
Turn the raw search text into the text passed to |
|
Return |
|
The records this request may search |
|
The records used for labels, for example with |
|
The text shown for a record |
|
Text fields that put the closest matches first, defaulting to |
|
Apply |
|
Replace the search entirely; must return something sliceable |
|
Load the records for a form’s value; |
|
The unique field to submit, defaulting to |
key_field must match the form field’s to_field_name, which is set automatically for a
ForeignKey with to_field. izaya raises ImproperlyConfigured if they differ.
Results are cut off at max_results, so when a common word matches more records than that, the
best match can be lost. rank_fields puts the closest matches first:
class CharacterLookup(ModelLookup):
model = Character
search_fields = ["name__unaccent__icontains", "alias__icontains"]
rank_fields = ["name__unaccent"]
Unlike search_fields, these are field names without a lookup, and only change the order. A record
ranks by its best match in any of them: the whole value, then the start of the value, then the start
of a word, then everything else. Ties keep the order of get_queryset, or the model’s
Meta.ordering, then fall back to the primary key. rank_fields can’t cross a to-many relation,
which the system check izaya.E001 reports. Every match has to be ranked before the results are cut
off, so measure this on large tables. Ranking is tested on SQLite, PostgreSQL, MySQL and MariaDB.
On MySQL and MariaDB the default _ai_ci collations ignore accents when matching the whole value or
its start, but not the start of a word, so for cafe “Café” ranks first while “Le Café” ranks
with everything else.
A search override keeps its own order unless it calls rank, which raises ImproperlyConfigured
for a sliced or combined queryset, or one using distinct() with field names.
For data that isn’t a model, subclass Lookup and implement search and get_selected, returning
(key, label) pairs. On a field with choices, the widget only renders labels for keys among them;
see Private data for fields without choices.