django templates
javascript
django views
data passing
django scripting

How can I use the variables from views.py in JavasScript, script/script in a Django template?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In a Django application you frequently need to send data from the server (Python) to the browser (JavaScript). Because Django templates render on the server before the HTML reaches the client, you must serialize your Python variables into a format that JavaScript can read. This article covers four reliable techniques, from the simplest template tag approach to a full REST API, so you can choose the one that fits your project.

Passing Data Through Template Context

The most direct method is to render a Python variable straight into a \<script> block. In your view you add the variable to the context dictionary, and in the template you use Django's {{ }} tag to inject it.

python
1# views.py
2from django.shortcuts import render
3
4def dashboard(request):
5    context = {
6        "username": "Alice",
7        "score": 42,
8    }
9    return render(request, "dashboard.html", context)
html
1<!-- dashboard.html -->
2<script>
3  const username = "{{ username }}";
4  const score = {{ score }};
5  console.log(username, score);
6</script>

This works for simple scalar values, but it breaks when the data contains quotes, angle brackets, or other characters that interfere with HTML or JavaScript parsing. For anything beyond plain numbers or pre-sanitized short strings, you should use one of the safer approaches below.

Using the json_script Filter

Django 2.1 introduced the json_script template filter specifically for passing data to JavaScript safely. It serializes the value to JSON inside a \<script type="application/json"> tag, automatically escaping characters like \<, >, and & that could lead to cross-site scripting (XSS).

python
1# views.py
2from django.shortcuts import render
3
4def dashboard(request):
5    user_data = {
6        "name": "Alice",
7        "tags": ["admin", "editor"],
8        "bio": 'Enjoys <scripting> & "coding"',
9    }
10    return render(request, "dashboard.html", {"user_data": user_data})
html
1<!-- dashboard.html -->
2{{ user_data|json_script:"user-data" }}
3
4<script>
5  const userData = JSON.parse(
6    document.getElementById("user-data").textContent
7  );
8  console.log(userData.name);   // Alice
9  console.log(userData.tags);   // ["admin", "editor"]
10</script>

The filter writes the JSON into a hidden script element with the given id. Your JavaScript then reads and parses it. Because the serialization and escaping happen on the server, this approach is both XSS-safe and easy to use.

Using HTML Data Attributes

If you only need to pass a small number of values and prefer to keep your JavaScript in external files (where Django template tags are not available), you can attach data to an HTML element with data-* attributes.

python
1# views.py
2import json
3from django.shortcuts import render
4from django.utils.safestring import mark_safe
5
6def dashboard(request):
7    config = {"theme": "dark", "refresh_interval": 30}
8    return render(request, "dashboard.html", {
9        "config_json": mark_safe(json.dumps(config)),
10    })
html
1<!-- dashboard.html -->
2<div id="app" data-config='{{ config_json }}'></div>
3
4<script src="/static/js/app.js"></script>
javascript
1// static/js/app.js
2const el = document.getElementById("app");
3const config = JSON.parse(el.dataset.config);
4console.log(config.theme);  // "dark"

Be careful with mark_safe: it tells Django to skip auto-escaping, so you must ensure the data is safe before marking it. For untrusted user input, prefer json_script instead.

Fetching Data from a DRF API Endpoint

For complex or frequently updated data, the cleanest architecture is to serve it through a dedicated API endpoint using Django REST Framework (DRF). The template loads with no embedded data, and JavaScript fetches what it needs asynchronously.

python
1# views.py (API)
2from rest_framework.decorators import api_view
3from rest_framework.response import Response
4
5@api_view(["GET"])
6def user_stats(request):
7    return Response({
8        "username": request.user.username,
9        "score": 42,
10        "rank": 7,
11    })
javascript
1// static/js/app.js
2async function loadStats() {
3  const response = await fetch("/api/user-stats/", {
4    headers: { "X-CSRFToken": getCookie("csrftoken") },
5  });
6  const data = await response.json();
7  document.getElementById("score").textContent = data.score;
8}
9
10loadStats();

This approach separates concerns cleanly: Django serves HTML, DRF serves data, and JavaScript handles rendering. It also makes it trivial to reuse the same endpoint for mobile apps or third-party integrations.

Common Pitfalls

  • XSS through unescaped context variables: Injecting {{ variable }} directly into a \<script> block without the json_script filter can allow script injection if the variable contains user-supplied content.
  • Forgetting the CSRF token on fetch requests: Django rejects POST, PUT, and DELETE requests that lack a valid CSRF token. Always include the X-CSRFToken header when calling your own API from JavaScript.
  • Using safe or mark_safe on untrusted data: These functions disable Django's auto-escaping. Apply them only to data you have sanitized yourself, such as the output of json.dumps() on server-controlled values.
  • Embedding large datasets in the template: Serializing thousands of rows into the HTML increases page weight and time-to-first-byte. For large payloads, use an API endpoint with pagination instead.
  • Assuming template tags work in external .js files: Django only processes template tags inside template files. If your JavaScript lives in a static file, use data-* attributes, json_script, or an API call to pass the data.

Summary

  • For simple, trusted scalar values, render them directly into a \<script> block via Django template context variables.
  • For structured or user-supplied data, use Django's built-in json_script filter, which handles JSON serialization and XSS escaping automatically.
  • For external JavaScript files, attach data to HTML elements with data-* attributes and read them with element.dataset.
  • For complex or frequently changing data, create a DRF API endpoint and fetch the data asynchronously with JavaScript.
  • Always consider security: avoid mark_safe on untrusted input, include CSRF tokens on mutating requests, and prefer json_script over raw variable injection.

Course illustration
Course illustration

All Rights Reserved.