Skip to content

MagiFiltersForm

deby edited this page Dec 6, 2021 · 15 revisions

↑ 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

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

Search / ordering fields

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': '',
    }

Configure fields

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')

Buttons below search button

Buttons below search button

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.

Presets (or "Suggestions")

A list of suggestions of search can be displayed for users who may not be confident using the filters manually:

Example of suggestions

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.

Merge fields

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'],
    ]
    ...

Merged fields

Custom field name

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'],
    }
    ...
Custom label

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'),
        },
    }
Custom fields details

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', {}),
        ]),
    ]
    ...
Custom field details with hidden fields available

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')
    ...
Re-order fields

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.

CuteForm

💡 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

  1. Collections
    1. MagiModel
    2. MagiCollection
    3. MagiForm
    4. MagiFiltersForm
    5. MagiFields
  2. Single pages
  3. Configuring the navbar

III. References

IV. Utils

V. Advanced tutorials

VI. More

Clone this wiki locally