As far as I understand, the commonly accepted way to use crispy-forms with django-filter is to override the form property like so:
import django_filters
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column
class ProductFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='iexact')
@property
def form(self):
form = super().form
form.helper = FormHelper(form)
form.helper.layout = Layout(
Row(
Column('price'),
Column('release_date'),
),
Submit("submit", "Apply filter")
)
return form
class Meta:
model = Product
fields = ['price', 'release_date']
This solution works, but it recreates a new FormHelper and Layout every time the property is accessed.
I know I could cache the values, but since I need to do this in most filters, I wish there were a DRYer solution.
I understand I could also create a new Form derivative and specify in Meta.form but I think creating a class for this is overkill. Besides, the definition of this class, and therefore the construction of the layout, would have to be above the definition of the filters, which feels very unnatural.
I suggest adding a new hook, get_form() that would be called when the form is created:
class BaseFilterSet:
...
@property
def form(self):
if not hasattr(self, "_form"):
self._form = self.get_form()
return self._form
def get_form(self):
Form = self.get_form_class()
if self.is_bound:
return Form(self.data, prefix=self.form_prefix)
else:
return Form(prefix=self.form_prefix)
I mentioned FormHelper and Layout as examples, but I'm sure there are other last-minute form customizations that users could do with this hook.
I know you've been reluctant to add hooks in the past (e.g., #1630), but I think this one perfectly aligns with the design of the library and with the rest of the Django ecosystem; for example, FormView.get_form() and ModelAdmin.get_form().
Hi there,
Thank you for this awesome library :heart:
As far as I understand, the commonly accepted way to use crispy-forms with django-filter is to override the
form
property like so:This solution works, but it recreates a new
FormHelper
andLayout
every time the property is accessed. I know I could cache the values, but since I need to do this in most filters, I wish there were a DRYer solution.I understand I could also create a new
Form
derivative and specify inMeta.form
but I think creating a class for this is overkill. Besides, the definition of this class, and therefore the construction of the layout, would have to be above the definition of the filters, which feels very unnatural.I suggest adding a new hook,
get_form()
that would be called when the form is created:I mentioned
FormHelper
andLayout
as examples, but I'm sure there are other last-minute form customizations that users could do with this hook.I know you've been reluctant to add hooks in the past (e.g., #1630), but I think this one perfectly aligns with the design of the library and with the rest of the Django ecosystem; for example,
FormView.get_form()
andModelAdmin.get_form()
.I can write a PR if you want.
Best regards, Benoit