---
url: https://lune-js.com/integrations/django.md
---
# Django Integration Guide

Lune is an excellent companion for Django applications. It allows you to add interactivity to your templates while keeping your backend logic in Python.

## Installation

The easiest way to use Lune in Django is by adding a `<script>` tag to your base template.

```html
<!-- base.html -->
<head>
  <script src="https://cdn.jsdelivr.net/npm/lune-js" defer init></script>
</head>
```

## Data Injection

You can pass data from your Django views directly into `lu-scope` by serializing it as JSON.

### In your Django View:

```python
import json
from django.shortcuts import render

def profile_view(request):
    user_data = {
        'username': request.user.username,
        'email': request.user.email,
        'is_premium': True
    }
    return render(request, 'profile.html', {
        'user_json': json.dumps(user_data)
    })
```

### In your Django Template:

Use the `safe` filter to prevent Django from escaping the JSON string.

```html
<div lu-scope="{{ user_json|safe }}">
  <p>Username: {{ username }}</p>
  <p lu-if="is_premium">Premium User Badge</p>
</div>
```

## CSRF Token Handling

Django requires a CSRF token for any POST, PUT, or DELETE requests.

### Option 1: Reading from Meta Tag

Add the token to a meta tag in your `base.html`:

```html
<meta name="csrf-token" content="{{ csrf_token }}" />
```

Then access it in your Lune methods:

```js
function submitForm() {
  const token = document.querySelector('meta[name="csrf-token"]').content;
  fetch("/api/save/", {
    method: "POST",
    headers: {
      "X-CSRFToken": token,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(this.formData)
  });
}
```

## Practical Examples

### 1. Progressive Form Validation

Enhance your existing Django forms with real-time validation.

```html
<script type="module">
  import { createApp } from "lune-js";

  function UsernameForm() {
    return {
      username: "",
      get isValid() {
        return this.username.length >= 3;
      }
    };
  }

  createApp({ UsernameForm }).mount();
</script>

<form method="POST" lu-scope="UsernameForm()">
  {% csrf_token %}
  <input type="text" name="username" lu-model="username" />
  <p lu-show="username && !isValid" style="color: red;">Username must be at least 3 characters.</p>
  <button :disabled="!isValid">Submit</button>
</form>
```

> \[!TIP]
> Derived values such as `isValid` live in a factory function: an object literal written inside
> `lu-scope` holds data only, so getters and methods go in JavaScript.

### 2. Dynamic Dependent Dropdowns

Update a second dropdown based on the selection of the first.

```html
<script type="module">
  import { createApp } from "lune-js";

  function CategoryPicker() {
    return {
      selectedCategory: "",
      categories: {
        fruits: ["Apple", "Banana"],
        veggies: ["Carrot", "Potato"]
      },
      get currentItems() {
        return this.categories[this.selectedCategory] || [];
      }
    };
  }

  createApp({ CategoryPicker }).mount();
</script>

<div lu-scope="CategoryPicker()">
  <select lu-model="selectedCategory">
    <option value="">Select Category</option>
    <option value="fruits">Fruits</option>
    <option value="veggies">Vegetables</option>
  </select>

  <select :disabled="!selectedCategory">
    <option lu-for="item in currentItems">{{ item }}</option>
  </select>
</div>
```

## Handling Template Conflicts

Since both Django and Lune use {{ }} for interpolation, you have two options:

### 1. Escape the braces

Wrap the Lune content in `{% verbatim %}` tags.

```html
{% verbatim %}
<div>{{ pico_vue_variable }}</div>
{% endverbatim %}
```

### 2. Change Lune delimiters

Configure Lune to use different delimiters.

```js
createApp({
  $delimiters: ["[[", "]]"]
}).mount();
```

Template:

```html
<div>[[ pico_vue_variable ]]</div>
```
