文章
Django - AJAX Requests, HTMX & CSRF Tokens
本教程依赖环境:
- Django
- HTMX
- DaysiUI
可参考教程:
示例:
core/models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=128)
description = models.TextField()
published = models.BooleanField(default=False)
def __str__(self):
return self.title
执行:
python manage.py makemigrations
python manage.py migrate
core/admin.py
from django.contrib import admin
from core.models import Article
admin.site.register(Article)
创建django用户登录后台添加几条Article记录
core/views.py
from django.shortcuts import render
from django.views.decorators.http import require_http_methods
from core.models import Article
def article_list(request):
context = {"articles": Article.objects.all()}
return render(request, "article_list.html", context)
@require_http_methods(["POST"])
def publish_article(request, pk):
article = get_object_or_404(Article, pk=pk)
article.published = True
article.save()
return render(request, "article_row.html", {"article": article})
core/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name="index"),
path('articles/', views.article_list, name="article_list"),
path('publish_article/<int:pk>/', views.publish_article, name="publish_article"),
]
模板配置:
base.html
{% load django_vite %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django & Vite</title>
<style>[x-cloak]{display:none}</style>
{% vite_hmr_client %}
{% vite_asset 'static/js/main.js' %}
</head>
<body class="p-12 text-4xl" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
<div class="m-12">
{% block content %}
{% endblock %}
</div>
</body>
</html>
修改内容:
<body class="p-12 text-4xl" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
article_list.html
{% extends 'base.html' %}
{% block content %}
<div class="w-6xl">
<h1 class="text-2xl font-bold mb-4">Articles</h1>
<div class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
<tr>
<th class="text-left">Tile</th>
<th class="text-left">Description</th>
<th class="text-left">Published</th>
<th class="text-left">Actions</th>
</tr>
</thead>
<tbody>
{% for article in articles %}
{% include 'article-row.html' %}
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
article_row.html
<tr>
<td>{{ article.title }}</td>
<td>{{ article.description }}</td>
<td>
{% if article.published %}
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current"
fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
{% else %}
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current"
fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
{% endif %}
</td>
<td>
{% if not article.published %}
<button class="btn btn-success publish-button"
hx-post="{% url 'publish_article' article.pk %}"
hx-target="closest tr"
hx-swap="outerHTML"
>
Publish
</button>
{% endif %}
</td>
</tr>
