I want to do something simple while using Crispy Forms; I want show a Fieldset only if the user belongs to the staff group. This is easily solved in a standard templates like this:
{% if user.is_staff %}
show extra stuff
{% endif %}
Maybe I missed something in the manual, but I don't see how I can just inject a template tag like "{% if user.is_staff %}" into the crispy form Layout. It would be ideal for my use case if I could something like the following where I use a fictitious 'Djangotag' to solve my problem:
self.helper.layout = Layout(
Fieldset(
'Section One',
'name',
'description',
),
Djangotag('{% if user.is_staff %}'),
Fieldset(
'Conditional Fieldset',
'field1',
'field2',
),
Djangotag('{% endif %}'),
Fieldset(
'More Details',
'detail1',
'detail2',
),
)
Is there an easy way to do this with crispy forms?
Note: I already implemented the self.user = kwargs.pop('user')
approach and it's not very elegant, I am still looking for something better.
I also tried created simple templates for the if statements, and tried this, HTML("{% include 'helpers/is_staff.html' %}"),
but the render process fails.
You can pass the request context to your form from the view, and then use this in your form helper. Something like this:
In the view function that creates the form:
form = MyForm(request.POST, user=getattr(request, 'user', None))
Then in your form's __init__
method:
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(MyForm, self).__init__(args, kwargs)
And finally in your form layout code:
if user and user.is_staff:
self.helper.layout.append(Fieldset(
'Conditional Fieldset',
'field1',
'field2',
),
I've just appended this fieldset to the end of the layout. The documentation gives you other options for updating layouts on the fly.
I didn't find a cleaner way, so I completed it the way I had started.
Here's the view...
class ModelCreateView(LoginRequiredMixin, CreateView):
....
def get_form_kwargs(self):
# I am going to stuff the user object into the view so that
# I can use it in ModelForm to check the user and build the form
# conditionally
kwargs = super(ModelCreateView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
In the ModelForm it was easiest to assume that the fields were always needed -- so I declared them all in the meta section -- then conditionally delete the fields, and conditionally append the form...
class YourCrispyForm(forms.ModelForm):
....
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(YourCrispyForm, self).__init__(*args, **kwargs)
# remove conditional fields
if self.user and self.user.is_staff:
pass
else:
del self.fields['field_name']
del self.fields['field_name']
del self.fields['field_name']
if self.user and self.user.is_staff:
self.helper.layout.append(
Fieldset(
'Conditional Sections',
Row(
Div('field_name', css_class="col-md-2"),
Div('field_name', css_class="col-md-2"),
...
),
)
)
It took me awhile to realizing that the deletion was the way to go. Hope that helps someone down the line.