Question

Inspecting the field.html template in the bootstrap3 template pack of django-crispyforms, I noticed an additional context variable, "tag", referenced. You can see this on line 12 and line 41 of the template. How can I specify a value for "tag" in the context used to render the field.html template for a particular form field?

Was it helpful?

Solution 3

The tag context variable is set in the template, not the view. If you're using the built-in bootstrap3 template pack it's defined in the template that is including field.html. If the including template does not define tag then it defaults to div.

Ex: table_inline_formset.html line 41.

OTHER TIPS

I used palestamp's response as a guide to build a more generic CustomCrispyField. You can pass extra_context as a kwarg to CustomCrispyField. extra_context is just a dictionary that I access in my custom template that I copied from crispy_forms.

from crispy_forms.layout import Field
from crispy_forms.utils import TEMPLATE_PACK


class CustomCrispyField(Field):
    extra_context = {}

    def __init__(self, *args, **kwargs):
        self.extra_context = kwargs.pop('extra_context', self.extra_context)
        super(CustomCrispyField, self).__init__(*args, **kwargs)

    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, extra_context=None, **kwargs):
        if self.extra_context:
            extra_context = extra_context.update(self.extra_context) if extra_context else self.extra_context
        return super(CustomCrispyField, self).render(form, form_style, context, template_pack, extra_context, **kwargs)

And I would use it like so in my form:

self.helper.layout=Div(CustomCrispyField('my_model_field', css_class="col-xs-3", template='general/custom.html', extra_context={'css_class_extra': 'value1', 'caption': 'value2'})

And my template would have code similar to the following:

{% crispy_field field %}
<button class="btn {{ css_class_extra }}">{{ caption }}</button>

You can just override standard crispy Field like this:

class LinkField(Field):
    def __init__(self, *args, **kwargs):
        self.view_name = kwargs.pop('view_name')
        super(LinkField, self).__init__(*args, **kwargs)

    def render(self, form, form_style, context, template_pack=CRISPY_TEMPLATE_PACK):
        if hasattr(self, 'wrapper_class'):
            context['wrapper_class'] = self.wrapper_class

        if hasattr(self, 'view_name'):
            context['view_name'] = self.view_name
        html = ''

        for field in self.fields:
            html += render_field(field, form, form_style, context, template=self.template, attrs=self.attrs, template_pack=template_pack)
        return html

Then just pass additional variable ('view_name') in overridden template.

In Layout it will look like this:

Layout(
    LinkField('field_name', template='path_to_overridden_template',
                      view_name='variable_to_pass')
)

following bobort's answer, I would like to highlight that you therefor can use any queryset as arguments in the extra_content, which allows you to inject via the custom template an html rendering of anything you want, this becomes very interesting concept on how to transform the crispy forms into super agile. I am currently using forms to render my templates, instead of rendering forms in templates ^^

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top