django crispy forms with jinja2

Well, Geoffrey R.'s answer is a good approach, but the wrong method of jinja2 is used. Instead of render_crispy_form, it should be as_crispy_form. So, from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form should be written at the beginning.

The corrected example jinja2.py file is as follows.

from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form # this line is different

from django.contrib import messages
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from django.utils import translation
from jinja2 import Environment


def environment(**options):
    env = Environment(
        extensions=["jinja2.ext.i18n", "jinja2.ext.with_"], **options
    )
    env.globals.update(
        {
            "get_messages": messages.get_messages,
            "static": staticfiles_storage.url,
            "crispy": as_crispy_form,  # this line is different
            "url": reverse,
        }
    )
    env.install_gettext_translations(translation)
    return env

Other steps are same with Geoffrey R.'s answer.


It works for me, with the following pip packages:

Django==3.1.2
django-crispy-forms==1.9.2
Jinja2==2.11.2

By the way, I'm not using the django-jinja pip package.

Thanks Geoffrey R. for his great idea.


Better solution:

templatetags.py

from crispy_forms.utils import render_crispy_form
from django_jinja import library
from jinja2 import contextfunction


@contextfunction
@library.global_function
def crispy(context, form):
    return render_crispy_form(form, context=context)

In template:

{{ crispy(form) }}

I found an easy, but not completed way to "hack in".

  1. use 'django-jinja' package to register new filters;
  2. in the filter file, define a crispy filter, which looks like:

    from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form
    def crispy(form):
        return as_crispy_form(form, 'Bootstrap3', form.helper.label_class, form.helper.field_class)
    

In the form Jinja template, I have to write more code than direct crispy tag in django template:

<form id='id_form' class="form-horizontal" method='post'>
    {% csrf_token %}
    {{form.media}}
    {{ form|crispy() }}
    <div>
        <input type="submit" name="submit" value="Submit" class="btn btn-primary" id="submit-id-submit">
    </div>
</form>

If anyone finds a more effective way to crispy forms, please let me know.