Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
25 changes: 25 additions & 0 deletions rest_framework/jinja2.py
Original file line number Diff line number Diff line change
@@ -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 {})
66 changes: 66 additions & 0 deletions tests/test_jinja2_templates.py
Original file line number Diff line number Diff line change
@@ -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 (
"<form" in output or "name" in output.lower()
), "Expected form rendering to contain field data"
assert "Mohammed" in output, "Expected rendered form to contain the serializer data"


def test_jinja2_render_field_individual():
"""
Test that render_field works individually in Jinja2.
"""
Environment, DRFExtension = load_jinja()
env = Environment(extensions=[DRFExtension])
template_str = "{{ render_field(serializer.name) }}"
template = env.from_string(template_str)

serializer = SimpleSerializer(data={"name": "Ahmed", "age": 25})
serializer.is_valid()

output = template.render(serializer=serializer)

assert (
"Ahmed" in output or "name" in output.lower()
), "Expected field rendering to work"
Loading