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.
<!-- 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:
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.
<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:
<meta name="csrf-token" content="{{ csrf_token }}" />Then access it in your Lune methods:
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.
<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.
<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.
{% verbatim %}
<div>{{ pico_vue_variable }}</div>
{% endverbatim %}2. Change Lune delimiters
Configure Lune to use different delimiters.
createApp({
$delimiters: ["[[", "]]"]
}).mount();Template:
<div>[[ pico_vue_variable ]]</div>