diff --git a/pyproject.toml b/pyproject.toml index 530346c6d7..4cda6597dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ optional = [ "django-filter", "django-guardian>=2.4.0,<3.4", "inflection==0.5.1", + "jinja2>=3.0", "legacy-cgi; python_version>='3.13'", "markdown>=3.3.7", "psycopg[binary]>=3.1.8", diff --git a/rest_framework/jinja2.py b/rest_framework/jinja2.py new file mode 100644 index 0000000000..7a92ffecfc --- /dev/null +++ b/rest_framework/jinja2.py @@ -0,0 +1,25 @@ +from jinja2.ext import Extension + +from rest_framework.renderers import HTMLFormRenderer + + +class DRFExtension(Extension): + """Jinja2 extension exposing DRF template rendering functions.""" + + def __init__(self, environment): + super().__init__(environment) + environment.globals["render_form"] = self.render_form + environment.globals["render_field"] = self.render_field + + def render_form(self, serializer, style=None): + """Render a complete HTML form for the given serializer.""" + renderer = HTMLFormRenderer() + return renderer.render( + serializer.data, + renderer_context={"serializer": serializer, "style": style or {}}, + ) + + def render_field(self, field, style=None): + """Render an individual HTML field.""" + renderer = HTMLFormRenderer() + return renderer.render_field(field, style or {}) diff --git a/tests/test_jinja2_templates.py b/tests/test_jinja2_templates.py new file mode 100644 index 0000000000..214d279b0b --- /dev/null +++ b/tests/test_jinja2_templates.py @@ -0,0 +1,66 @@ +import importlib + +import pytest + +from rest_framework import serializers + + +def load_jinja(): + pytest.importorskip("jinja2") + jinja2 = importlib.import_module("jinja2") + DRFExtension = importlib.import_module("rest_framework.jinja2").DRFExtension + return jinja2.Environment, DRFExtension + + +class SimpleSerializer(serializers.Serializer): + name = serializers.CharField() + age = serializers.IntegerField() + + +def test_jinja2_render_form_with_extension(): + """ + Test that the DRF Jinja2 extension correctly exposes render_form + and render_field to the Jinja2 environment. + """ + Environment, DRFExtension = load_jinja() + + # Setup Jinja2 environment with the new DRF extension + env = Environment(extensions=[DRFExtension]) + + # Create a template that uses the DRF rendering functions + template_str = """ + {% set form_data = render_form(serializer) %} + {{ form_data }} + """ + template = env.from_string(template_str) + + serializer = SimpleSerializer(data={"name": "Mohammed", "age": 30}) + serializer.is_valid() + + # Render the template + output = template.render(serializer=serializer) + + # Assertions: Verify the output contains expected HTML form elements + assert ( + "