-
Notifications
You must be signed in to change notification settings - Fork 11
MagiFiltersForm
↑ Parent: Collections
← Previous: MagiForm
You can add a side bar to your list view to allow users to search and filter through the items in the collection. To do so, you need to create a class in forms.py
that inherits from MagiFiltersForm
.
While MagiFiltersForm
is very similar to MagiForm
(it inherits from it), it doesn't have any logic to "save" an item.
It provides a method filter_queryset
that takes a queryset, the parameters (as a dictionary), the current request and returns a queryset. You may override this method if needed (and call its super).
If your collection provides alt views, a selector to pick the view will also be available in the side bar filters.
-
in
magicollections.py
:from magi.magicollections import MagiCollection from . import forms class CardCollection(MagiCollection): ... class ListView(MagiCollection.ListView): ... filter_form = forms.CardFilterForm
-
in
forms.py
:from magi.forms import MagiFiltersForm from . import models class CardFilterForm(MagiFiltersForm): class Meta: model = models.Card
Search and ordering fields are provided by default, but you need to specify search_fields
and ordering_fields
to enable them.
from magi.forms import MagiFiltersForm
from . import models
class CardFilterForm(MagiFiltersForm):
search_fields = ['name', 'skill_name']
ordering_fields = [
('id', _('ID')),
('performance_max', _('Performance')),
]
class Meta:
model = models.Card
If one or more of the labels of the fields specified for search can't be found, the help text of the search field will end with , ...
. To specify the label, you can use search_fields_labels
. If you don't want it to show up at all, you can use ''
.
class CardFilterForm(MagiFiltersForm):
search_fields = ['name', 'skill_name', 'idol__name', 'secret_search_field']
search_fields_labels = {
'idol__name': _('Idol'),
'secret_search_field': '',
}
For most fields, the default behavior of MagiFiltersForm
is enough. Fields like NullBooleanFields or MultipleChoiceFields are already handled.
But for some fields that are not direct fields of the model or to handle special cases, you may provide some configuration for that field.
To do so, just provide an attribute {name}_filter
where {name}
is the corresponding field name. It has to be an instance of MagiFilter
, to which you can pass some named parameters. To see the full parameters you can provide to a MagiFilter
, refer to MagiFiltersForm settings.
from django import forms
from django.db.models.fields import BLANK_CHOICE_DASH
from magi.forms import MagiFiltersForm, MagiFilter
from bang import models
class CardFilterForm(MagiFiltersForm):
member_band = forms.ChoiceField(choices=BLANK_CHOICE_DASH + models.BAND_CHOICES, initial=None, label=_('Band'))
member_band_filter = MagiFilter(selector='member__i_band')
class Meta:
model = models.Card
fields = ('member_id', 'member_band')
By default, 3 buttons can appear under the search button:
- Random: will redirect to a random item that matches the search
- Suggestions: will display a list of suggestions (see presets)
- Clear: will clear the form to its default options
You can change the buttons by overriding the extra_buttons
method in the form.
The URL to clear can be specified using get_clear_url
in List view.
See details of the extra_buttons
method in MagiFiltersForm settings.
A list of suggestions of search can be displayed for users who may not be confident using the filters manually:
These are also very useful for SEO purpose, so it's recommended to set up a few for the main collections.
presetsFromChoices
can be used to create presets based on i_ choices.
presetsFromCharacters
can be used to create preset based on what's in FAVORITE_CHARACTERS
. See Characters.
Example:
class CardFilterForm(MagiFiltersForm):
...
presets = OrderedDict(
presetsFromChoices(models.Card, 'rarity')
+ presetsFromCharacters('idol')
+ [
('event-cards', {
'verbose_name': _('Event'),
'fields': {
'is_event': True,
'is_promo': False,
},
'icon': 'event',
}),
]
)
You can find all the details of what can be configured in a preset in MagiFiltersForm settings.
It's possible to merge multiple choice filters into one, when it makes sense.
For example, let's say a character can be in a group and a team. The teams can only be part of one group, so it wouldn't make sense to allow to filter by both group and team at the same time. In that case, merging the filters into one would make sense.
${PROJECT}/models.py
:
class Character(MagiModel):
...
GROUP_CHOICES = [
'Group A', 'Group B', 'Group C',
]
i_group = models.PositiveIntegerField(_('Group'), choices=i_choices(GROUP_CHOICES))
TEAM_CHOICES = [
'Team 1', 'Team 2', 'Team 3',
]
i_team = models.PositiveIntegerField(_('Team'), choices=i_choices(TEAM_CHOICES))
${PROJECT}/forms.py
:
class CharacterFilterForm(MagiFiltersForm):
merge_fields = [
['i_group', 'i_team'],
]
...
You can customize the name of the resulting fields by providing a dictionary instead of a list:
${PROJECT}/forms.py
:
class CharacterFilterForm(MagiFiltersForm):
merge_fields = {
'group_or_team': ['i_group', 'i_team'],
}
...
If you want to specify the label of the resulting merged field, you can replace your fields with a dictionary containing fields
and label
:
${PROJECT}/forms.py
:
class CardFilterForm(MagiFiltersForm):
merge_fields = {
'group_or_team': {
'fields': ['i_group', 'i_team'],
'label': _('Best team or group'),
},
}
You can customize some details per field by providing a dictionary instead of a string for each field:
${PROJECT}/forms.py
:
class CardFilterForm(MagiFiltersForm):
merge_fields = [
OrderedDict([
('character', {
'label': _('Character'),
'choices': [(_id, _name) for _id, _name, _image in FAVORITE_CHARACTERS],
'filter': MagiFilter(selector='main_character'),
}),
('i_group', {}),
('i_team', {}),
]),
]
...
If you want the fields to be available by themselves as well (to allow for example ?i_group=1
), you can also configure the fields directly within the form as you'd normally do (see Configure fields). The fields will be available but hidden.
For example, this would be equivalent to the above:
${PROJECT}/forms.py
:
class CardFilterForm(MagiFiltersForm):
merge_fields = [
['character', 'i_group', 'i_team'],
]
character = forms.ChoiceField(
label=_('Character'),
choices=[(_id, _name) for _id, _name, _image in FAVORITE_CHARACTERS],
)
character_filter = MagiFilter(selector='main_character')
...
The created merged field will take the spot of the first field it's merging (in our example above, character
).
If none of the merged fields are present in the form, the merged field will appear at the end.
You can't specify its position in the Meta
fields
value because it's added dynamically, so if you want the merged field to appear somewhere specifically in your form, you can call reorder_fields.
💡 If you need to use a CuteForm for your merged field, you can call mergedFieldCuteForm
. See CuteForm.
ℹ︎ See also: MagiFiltersForm settings
→ Next: MagiFields
I. Introduction
II. Tutorials
III. References
- Files tree
- Default collections
- Default pages
- Website settings
- MagiCollection settings
- Abstract models
- Abstract collections
- MagiForm settings
- MagiFiltersForm settings
- Single pages settings
IV. Utils
-
MagiModel utils
- MagiModel images and files
- DateTime fields
- BaseAccount model
- Save choices values as integer rather than strings
- Store comma separated values
- Store dictionaries
- Store Markdown texts
- Translate fields values in multiple languages
- Store JSON
- More model field types
- Transform images before saving them
- Check choices at form level instead of model level
- Use an internal cache for foreign keys in models
- Customize views with MagiModel properties
- Events
- Form utils
- Python utils
- Templates utils
- Javascript utils
- Enable and disable existing collections and pages
- Translations
- Page titles and descriptions
- Characters
- Seasons
- Roles and permissions
- Allow your staff team to change configurations
- Custom users preferences and settings
- Background illustrations
- Activities tabs
- Corner popups
VI. More