Skip to content

Django - 快速指南

Django 是一个高级的 Python Web 框架,旨在快速开发安全且可维护的网站。它鼓励清晰、实用的设计,并遵循“不要重复你自己”(Don’t Repeat Yourself, DRY)原则。

注意:根据 BSD 许可证授权,由 Django 软件基金会(DSF)维护。

  • 2003 年始于劳伦斯世界报(Lawrence Journal-World newspaper)。
  • 2005 年 7 月公开发布。
  • 一个积极开发的开源项目,拥有庞大的社区。
  • 松耦合(Loosely Coupled):组件相互独立。
  • 代码更少(Less Code):减少样板代码。
  • DRY:避免冗余。
  • 快速开发(Fast Development):工具加快开发过程。
  • 清晰设计(Clean Design):提倡最佳实践。
  • 显式优于隐式(Explicit over Implicit):避免“魔法”。
  • ORM(Object-Relational Mapper):使用 Python 与数据库交互。
  • Admin 界面:自动化的站点管理。
  • URL 路由:清晰的 URL 设计。
  • 模板系统:将展示层与逻辑分离。
  • 表单处理:验证和处理。
  • 安全性:内置保护措施。
  • 可伸缩性:解耦的组件。
  • 多功能性:可以构建各种 Web 应用程序。
  • 内置丰富功能(Batteries Included):包含许多内置功能。
  • 开发服务器:用于测试的轻量级服务器。

Django 通常遵循 Model-View-Template(MVT)架构模式,这是常见的 Model-View-Controller(MVC)模式的一个变体。

  • Model:表示数据结构(通常是数据库表)。定义数据的字段和行为。
  • View:处理请求逻辑。它接收 HTTP 请求,与 Model 交互(如果需要),并通过渲染 Template 返回 HTTP 响应。
  • Template:定义展示层(HTML)。它包含数据的占位符(变量)以及 View 提供的基本逻辑(标签、过滤器)。
  • URL Dispatcher:将请求的 URL 映射到特定的 View。

在 MVT 中,“View” 更像 MVC 中的“Controller”(处理逻辑),而“Template” 更像 MVC 中的“View”(处理展示)。Django 本身处理了许多类似 Controller 的框架方面的工作(路由请求等)。

  1. 用户请求一个 URL。
  2. Django 的 URL Dispatcher 找到匹配的 URL 模式,并调用相关的 View。
  3. View 执行逻辑,可能与 Model 交互以获取或保存数据。
  4. View 选择一个 Template 并将数据(Context)传递给它。
  5. Template Engine 使用 Context 渲染 Template,生成 HTML。
  6. View 将渲染后的 HTML 作为 HttpResponse 返回给用户的浏览器。

设置 Django 开发环境包括安装 Python、Django 本身,通常还有一个数据库系统。

Django 需要 Python。请查阅具体 Django 版本的文档以了解兼容的 Python 版本(现代 Django 需要 Python 3.8+)。如果您没有安装 Python,请从 python.org 下载。使用 python --version 或 python3 --version 验证安装。

最佳实践: 使用虚拟环境来隔离项目依赖。使用以下命令创建一个虚拟环境:

$ python -m venv myenv
$ source myenv/bin/activate # 在 Linux/macOS 上
$ myenv\Scripts\activate # 在 Windows 上

激活虚拟环境后,使用 pip 安装 Django:

$ pip install Django

验证安装:

$ python -m django --version

Django 支持 PostgreSQL、MySQL、SQLite 和 Oracle。对于开发来说,SQLite 通常足够,并且无需单独的服务器设置(它在默认情况下已配置)。对于生产环境,通常使用更健壮的数据库,如 PostgreSQL 或 MySQL。您需要在虚拟环境中安装数据库服务器本身和相应的 Python 驱动程序(PostgreSQL 的 psycopg2-binary,MySQL 的 mysqlclient)。

在 settings.py 的 DATABASES 字典中配置您的数据库连接。

Django 包含一个轻量级的开发 Web 服务器(python manage.py runserver)。这不适合生产环境。对于部署,常见的选择包括使用 Gunicorn 或 uWSGI 运行在 Nginx 等反向代理后面,或使用 Apache 配合 mod_wsgi。

一个 Django Project 代表一个 Web 应用程序。

$ django-admin startproject myproject
myproject/
├── manage.py
└── myproject/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
  • manage.py:命令行工具。
  • settings.py:项目配置。
  • urls.py:主 URL 路由。
  • wsgi.py/asgi.py:服务器入口点。
  • 设置 DEBUG = True(仅用于开发)。
  • 配置 DATABASES(默认为 SQLite)。
  • 检查 INSTALLED_APPS、MIDDLEWARE、TEMPLATES、STATIC_URL。
$ python manage.py runserver

在浏览器中访问 http://127.0.0.1:8000/ 查看欢迎页面。

一个 Django 项目由 App 组成。App 是一个可重用的模块,处理特定的功能(例如,博客、投票)。

导航到您的项目目录(包含 manage.py 的目录),并运行:

$ python manage.py startapp myapp

这会创建一个 myapp 目录:

myapp/
├── __init__.py
├── admin.py # Admin 站点配置
├── apps.py # App 配置
├── migrations/ # 数据库迁移文件
│ └── __init__.py
├── models.py # 数据模型(数据库结构)
├── tests.py # 应用测试
└── views.py # 请求处理逻辑(视图)

将您的应用添加到项目 settings.py 文件中的 INSTALLED_APPS 列表。使用 myapp/apps.py 中找到的 App 配置类路径:

myproject/settings.py
INSTALLED_APPS = [
# ... 其他应用
'myapp.apps.MyappConfig', # 或者只写 'myapp'
'django.contrib.admin',
'django.contrib.auth',
# ... 更多默认应用
]
  1. 在 models.py 中定义模型。
  2. 运行 python manage.py makemigrations myapp 创建迁移文件。
  3. 运行 python manage.py migrate 将更改应用到数据库。
  4. 在 views.py 中创建视图来处理请求。
  5. 创建模板(例如,在 myapp/templates/myapp/ 中)用于展示。
  6. 在 myapp/urls.py 中定义 URL 模式,并将其包含在项目的 urls.py 中。
  7. 可选地,在 admin.py 中注册模型,以便通过 Admin 站点管理它们。
  8. 在 tests.py 中编写测试。

Django 的 Admin 是一个强大、自动生成的界面,用于管理您网站的内容。

  • 确保 django.contrib.admin 及其依赖项在 INSTALLED_APPS 中。
  • 确保所需的 Middleware(SessionMiddleware、AuthenticationMiddleware 等)在 MIDDLEWARE 中。
  • 在项目 urls.py 中包含 Admin URL:path('admin/', admin.site.urls)。
1. 运行迁移:`python manage.py migrate`
2. 创建超级用户:`python manage.py createsuperuser`

运行 python manage.py runserver 并访问 /admin/。使用超级用户凭据登录。

Admin 站点列出已注册的模型。您可以对模型实例执行 CRUD 操作(创建、读取、更新、删除)。要使您自己的模型可管理,请在应用的 admin.py 文件中注册它们。

myapp/admin.py 示例:

from django.contrib import admin
from .models import YourModel # 导入您的模型
admin.site.register(YourModel) # 注册您的模型

Views 处理请求逻辑并返回响应。它们位于 views.py 中。

myapp/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world!")
myapp/views.py
from django.shortcuts import render
import datetime
def current_time(request):
now = datetime.datetime.now()
return render(request, 'myapp/time.html', {'current_time': now})

myapp/templates/myapp/time.html:

<p>当前时间: {{ current_time }}</p>
myapp/views.py
from django.http import HttpResponse
def detail(request, item_id):
return HttpResponse(f"您正在查看 item {item_id}。")

参数从 URL 配置中捕获。

Django 使用 urls.py 文件将请求的 URL 映射到 Views。

URL 路由的主要入口点。它通常包含来自各个 App 的 URL。

myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('myapp/', include('myapp.urls')), # 包含 App 的 URL
]

定义特定于 App 的 URL 模式。

myapp/urls.py
from django.urls import path
from . import views
# app_name = 'myapp' # 可选:为 URL 添加命名空间
urlpatterns = [
path('', views.index, name='index'), # 例如,/myapp/
path('time/', views.current_time, name='current_time'), # 例如,/myapp/time/
path('item/<int:item_id>/', views.detail, name='detail'), # 例如,/myapp/item/5/
]

解释:

  • path():定义一个 URL 路由。
  • 第一个参数:URL 模式字符串。转换器(如 <int:item_id>)捕获 URL 的一部分并将其作为参数传递给 View。
  • 第二个参数:View 函数或基于类的 View 的 as_view() 方法。
  • name:URL 模式的唯一名称,用于反向解析 URL(例如,在模板中使用 {% url %})。

将展示层(HTML)与逻辑(Python)分离。

  • {{ variable }}:输出 Context 中变量的值。
  • {{ variable.attribute }}:访问属性。
  • {{ variable|filter }}:应用过滤器修改输出(例如,{{ name|lower }})。
  • {% tag %}:执行逻辑(例如,{% if %}、{% for %}、{% url %}、{% extends %})。
  • {% if condition %} … {% else %} … {% endif %}:条件判断。
  • {% for item in list %} … {% empty %} … {% endfor %}:循环。
  • {% extends 'base.html' %}:模板继承(必须是第一个标签)。
  • {% block block_name %} … {% endblock %}:在基础模板中定义可覆盖的块。
  • {% url 'url_name' arg1 arg2 %}:反向解析 URL。
  • {% load static %}:加载静态文件标签。
  • {% static 'path/to/file.css' %}:生成静态文件 URL。
  • {# comment #} 或 {% comment %} … {% endcomment %}:注释。

Views 通过 Context 字典将数据传递给 Templates:render(request, 'template.html', {'my_var': value})。

Models 定义了应用程序的数据结构,映射到数据库表。

myapp/models.py
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField('date published', default=timezone.now)
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
ordering = ['-published_date'] # 默认排序

解释:

  • 每个继承自 models.Model 的类代表一个数据库表。
  • 类属性是模型字段(CharField、TextField、DateTimeField、ForeignKey 等),代表表列。
  • ForeignKey、ManyToManyField、OneToOneField 定义关系。
  • on_delete=models.CASCADE:定义关联对象删除时的行为。
  • __str__:返回对象的可读字符串表示(用于 Admin)。
  • Meta 类:可选元数据(例如,默认排序、表名)。

更改模型后:

1. 创建迁移:`python manage.py makemigrations myapp`
2. 将迁移应用到数据库:`python manage.py migrate`

Django 提供了一个数据库抽象 API(ORM)。

from .models import Post
# 获取所有文章
all_posts = Post.objects.all()
# 通过主键 (pk) 获取特定文章
post = Post.objects.get(pk=1)
# 过滤文章
recent_posts = Post.objects.filter(published_date__year=2023)
# 创建新文章
new_post = Post.objects.create(title='新标题', content='...', author=request.user)
# 更新文章
post.title = '更新后的标题'
post.save()
# 删除文章
post.delete()

使用 django.shortcuts.redirect 将用户发送到不同的 URL。

from django.shortcuts import redirect
def old_view(request):
# 使用 URL 名称进行重定向(最佳实践)
return redirect('new_view_name', permanent=True)
def another_view(request):
# 使用硬编码路径进行重定向
return redirect('/some/other/path/')
def view_with_args(request, item_id):
# 带参数的重定向
return redirect('item_detail', pk=item_id)

redirect 的参数:

  • 一个模型实例(使用其 get_absolute_url() 方法)。
  • 一个 URL 名称(来自 urls.py)加上可选的位置参数/关键字参数。
  • 一个硬编码的 URL 路径字符串(例如,/myapp/home/)。
  • permanent=True 发送 301(永久)重定向,默认为 302(临时)。

使用 django.urls.reverse 获取 URL 字符串,而不是重定向(在模型或其他地方很有用)。

from django.urls import reverse
url = reverse('item_detail', kwargs={'pk': 5})
# url 将是 '/myapp/item/5/'(取决于您的 URLConf)

Django 提供了发送电子邮件的函数。

设置电子邮件后端和凭据:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 对于开发,可以使用控制台输出:
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '您的邮箱@example.com'
EMAIL_HOST_PASSWORD = '您的密码'
from django.core.mail import send_mail
send_mail(
'主题在此',
'消息内容在此。',
'from@example.com', # 发件人
['to@example.com'], # 收件人列表
fail_silently=False,
)
from django.core.mail import send_mail
html_message = '<p>这是**HTML**消息。</p>'
send_mail(
'HTML 主题',
'非 HTML 客户端的备用纯文本消息。', # 必填,用于非 HTML 客户端
'from@example.com',
['to@example.com'],
html_message=html_message,
)
from django.core.mail import EmailMessage
email = EmailMessage(
'你好',
'消息体在此',
'from@example.com',
['to1@example.com', 'to2@example.com'],
bcc=['bcc@example.com'],
reply_to=['another@example.com'],
headers={'Message-ID': 'foo'},
)
# email.attach('logo.png', img_data, 'image/png') # 附加文件
email.send()

基于类的 View,以最少的代码解决常见的 Web 开发模式(显示列表、详情页、表单等)。

  • TemplateView:渲染模板。
  • ListView:显示对象列表。
  • DetailView:显示单个对象的详情。
  • CreateView、UpdateView、DeleteView:处理用于创建、更新、删除对象的表单。
  • FormView:处理表单显示和处理。
myapp/views.py
from django.views.generic import ListView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'myapp/post_list.html' # 默认值: <app>/<model>_list.html
context_object_name = 'posts' # 默认值: object_list
paginate_by = 10 # 可选: 添加分页
myapp/urls.py
from django.urls import path
from .views import PostListView
urlpatterns = [
path('posts/', PostListView.as_view(), name='post_list'),
]
myapp/templates/myapp/post_list.html
<h1>文章列表</h1>
<ul>
{% for post in posts %}
<li><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></li>
{% empty %}
<li>暂无文章。</li>
{% endfor %}
</ul>
<!-- 如果使用 paginate_by,添加分页控制 -->

Django 的表单库处理表单渲染、验证和数据清洗。

myapp/forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)

在 Views 中使用 Forms(views.py):

Section titled “在 Views 中使用 Forms(views.py):”
myapp/views.py
from django.shortcuts import render, redirect
from .forms import ContactForm
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# 处理 form.cleaned_data 中的数据
name = form.cleaned_data['name']
email = form.cleaned_data['email']
# ... 发送邮件、保存到数据库等
return redirect('success_page') # POST 后重定向
else: # GET
form = ContactForm()
return render(request, 'myapp/contact.html', {'form': form})
myapp/templates/myapp/contact.html
<form method="post">
{% csrf_token %} <!-- 对于安全性至关重要 -->
{{ form.as_p }} <!-- 将字段渲染在 <p> 标签中 -->
<button type="submit">发送</button>
</form>

form.is_valid() 运行验证。错误可通过 form.errors、form.field_name.errors、form.non_field_errors 访问。通过表单类中的 clean_fieldname() 或 clean() 方法进行自定义验证。

处理用户上传的文件。

  • 安装 Pillow:pip install Pillow(用于 ImageField)。
  • 在 settings.py 中配置 MEDIA_ROOT(文件存储的文件系统路径)和 MEDIA_URL(服务这些文件的 URL 前缀)。
  • 配置 URL 模式以在开发期间提供媒体文件(参见 Django 文档)。
myapp/models.py
class UserProfile(models.Model):
user = models.OneToOneField('auth.User', on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
# 对于非图像文件使用 FileField
myapp/forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ['avatar'] # 或者在 forms.Form 中使用 forms.ImageField
myapp/views.py
def upload_avatar(request):
if request.method == 'POST':
# 将 request.FILES 传递给表单!
form = ProfileForm(request.POST, request.FILES, instance=request.user.userprofile)
if form.is_valid():
form.save()
return redirect('profile_view')
else:
form = ProfileForm(instance=request.user.userprofile)
return render(request, 'myapp/upload.html', {'form': form})
myapp/templates/myapp/upload.html
<!-- 重要:为文件上传添加 enctype -->
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">上传</button>
</form>

使用 Apache 部署 Django 通常使用 mod_wsgi。

安装并启用 Apache 服务器和 mod_wsgi。

Apache 配置(httpd.conf 或虚拟主机文件):

Section titled “Apache 配置(httpd.conf 或虚拟主机文件):”
# mod_wsgi 配置示例
WSGIScriptAlias / /path/to/your/myproject/myproject/wsgi.py
WSGIPythonHome /path/to/your/virtualenv
WSGIPythonPath /path/to/your/myproject
<Directory /path/to/your/myproject/myproject>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
# 静态文件别名(由 Apache 处理)
Alias /static/ /path/to/your/project/staticfiles/
<Directory /path/to/your/project/staticfiles>
Require all granted
</Directory>
# 媒体文件别名(由 Apache 处理)
Alias /media/ /path/to/your/project/mediafiles/
<Directory /path/to/your/project/mediafiles>
Require all granted
</Directory>

注意:

  • 将路径替换为您实际的项目/虚拟环境路径。
  • 确保 settings.py 中的 DEBUG = False。
  • 在 settings.py 中配置 ALLOWED_HOSTS。
  • 运行 python manage.py collectstatic 将静态文件收集到 STATIC_ROOT 指定的目录中(该目录应与上面 /path/to/your/project/staticfiles/ 匹配)。

一种非常常见的生产环境设置是使用 Gunicorn(或 uWSGI)作为应用程序服务器运行 Django,并在其前面使用 Nginx 作为反向代理。Nginx 处理传入请求,直接提供静态/媒体文件,并将动态请求转发给 Gunicorn。这种设置通常被认为性能更优且更灵活。

Cookie 在客户端浏览器上存储少量数据。

Cookies 在 HttpResponse 对象上设置。

from django.shortcuts import render
import datetime
def set_cookie_view(request):
response = render(request, 'myapp/cookie_set.html')
response.set_cookie(
'username',
'testuser',
max_age=3600, # 1 小时后过期
# expires=datetime.datetime.utcnow() + datetime.timedelta(days=7), # 7 天后过期(指定具体时间)
# httponly=True, # 推荐:JavaScript 无法访问
# secure=True, # 推荐:仅通过 HTTPS 发送
# samesite='Lax' # 推荐:CSRF 保护
)
return response

从 HttpRequest 对象的 COOKIES 字典中读取 Cookies。

def read_cookie_view(request):
username = request.COOKIES.get('username', 'Guest') # 使用 .get() 获取默认值
return render(request, 'myapp/cookie_read.html', {'username': username})
def delete_cookie_view(request):
response = render(request, 'myapp/cookie_deleted.html')
response.delete_cookie('username')
return response

注意:Cookies 是客户端的,用户可以修改。请勿将敏感信息直接存储在 Cookies 中。请改用 Django Sessions。

Sessions 允许在服务器端存储数据,这些数据与存储在客户端 Cookie 中的唯一会话 ID 相关联。对于用户数据而言,比普通 Cookie 更安全。

  • 确保 django.contrib.sessions 在 INSTALLED_APPS 中。
  • 确保 django.contrib.sessions.middleware.SessionMiddleware 在 MIDDLEWARE 中(通常默认包含)。
  • 运行 python manage.py migrate(如果使用基于数据库的 Session,这是默认设置)。

SESSION_ENGINE 设置控制存储方式(数据库、缓存数据库、文件、签名 Cookie)。

通过 request.session 字典访问 Session 数据。

def session_example_view(request):
# 设置 Session 值
request.session['favorite_color'] = 'blue'
# 获取 Session 值
fav_color = request.session.get('favorite_color', 'unknown')
# 检查键是否存在
if 'user_id' in request.session:
user_id = request.session['user_id']
# 删除 Session 值
if 'temp_data' in request.session:
del request.session['temp_data']
# 清空整个 Session(如果使用认证系统,这将导致用户注销)
# request.session.flush()
# 设置 Session 过期时间(例如,30 分钟不活动)
# request.session.set_expiry(1800)
return render(request, 'myapp/session_info.html', {'color': fav_color})

Session 在被修改时会自动保存。

Caching 存储耗时操作的结果,以提高性能。

配置 CACHES 设置。

CACHES = {
'default': { # 'default' 是标准别名
# Memcached(推荐用于生产环境)
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:11211',
# 或者使用 Redis(需要 django-redis 包)
# 'BACKEND': 'django_redis.cache.RedisCache',
# 'LOCATION': 'redis://127.0.0.1:6379/1',
# 或者数据库缓存
# 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
# 'LOCATION': 'my_cache_table', # 运行 createcachetable 命令
# 或者文件系统缓存
# 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
# 'LOCATION': '/var/tmp/django_cache',
# 或者本地内存缓存(进程内,主要用于开发)
# 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
# 'LOCATION': 'unique-snowflake',
}
}
  • 站点级: 在 MIDDLEWARE 中使用 UpdateCacheMiddleware 和 FetchFromCacheMiddleware。
  • 视图级: 在 View 函数上使用 @cache_page(timeout_seconds) 装饰器,或在 urls.py 中包装 View。
  • 模板片段级: 在模板中使用 {% load cache %} 和 {% cache timeout_seconds fragment_name %} ... {% endcache %}。
  • 低级 API: 在代码中直接使用 django.core.cache.cache.set('key', value, timeout) 和 cache.get('key')。

示例:视图级缓存

myapp/views.py
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 缓存 15 分钟
def expensive_view(request):
# ... 执行耗时的计算 ...
return render(request, 'myapp/results.html', context)

注意: 内置的 django.contrib.comments 框架已从 Django 1.8 版本开始从核心移除,并且已废弃。请勿在新项目中使用它。

  • 第三方 Django 应用: 在 PyPI 上搜索维护中的评论应用,如 django-comments-xtd,它构建在旧框架的概念之上。
  • 外部服务: 使用 JavaScript 片段集成托管的评论平台,如 Disqus 或 Commento。

您通常会创建一个 Comment 模型,包含 user(指向 User 的 ForeignKey)、content(TextField)、timestamp(DateTimeField)等字段,以及一个重要的 GenericForeignKey,用于将评论链接到任何其他模型实例(例如,一篇博客文章、一个产品等)。然后,您需要创建表单和视图来处理评论提交和显示。

由于该框架已废弃,此处省略了旧框架的详细实现步骤。

使用 django.contrib.syndication 生成 RSS 或 Atom Feed。

myapp/feeds.py
from django.contrib.syndication.views import Feed
from django.urls import reverse
from .models import Post # 假设有一个 Post 模型
class LatestPostsFeed(Feed):
title = "我的博客文章"
link = "/blog/"
description = "我博客的最新更新。"
def items(self):
return Post.objects.order_by('-published_date')[:5]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.content # 或摘要字段
# 如果模型有 get_absolute_url,则 item_link 是可选的
def item_link(self, item):
return reverse('post_detail', args=[item.pk])
myapp/urls.py
from django.urls import path
from .feeds import LatestPostsFeed
urlpatterns = [
# ... 其他 urls
path('latest/feed/', LatestPostsFeed(), name='post_feed'),
]

访问 Feed URL(例如,/myapp/latest/feed/)将生成 XML Feed。

AJAX(Asynchronous JavaScript and XML)允许网页动态更新内容,无需完全重新加载页面,通常通过在后台与服务器通信实现。

Django 中的现代 AJAX 通常涉及:

  1. 前端 JavaScript: 使用浏览器的 fetch API、Axios 等库,或框架(React、Vue、Angular)向 Django 后端发出异步 HTTP 请求(GET、POST 等)。
  2. Django 后端 View: 一个常规的 Django View,它接收 AJAX 请求,进行处理(例如,查询数据库、验证数据),并返回数据,通常使用 django.http.JsonResponse 返回 JSON 格式。
  3. URL Endpoint: urls.py 中的一个 URL 模式,映射到处理 AJAX 请求的 Django View。
  4. CSRF 处理: 确保通过 JavaScript 发送的 POST/PUT/DELETE 请求中包含 CSRF token。

注意: 以前版本中提到的旧库,如 django-dajaxice,通常不推荐使用或不再维护。请专注于标准前端 JS 和后端 JSON 响应。

  1. 模板 (like_button.html):
<button id="like-btn" data-post-id="{{ post.id }}" data-url="{% url 'like_post' %}">
赞 ({{ post.like_count }})
</button>
<script>
const likeBtn = document.getElementById('like-btn');
const postId = likeBtn.dataset.postId;
const url = likeBtn.dataset.url;
const csrftoken = getCookie('csrftoken'); // 获取 CSRF cookie 值的方法
likeBtn.addEventListener('click', () => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
},
body: JSON.stringify({ post_id: postId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
likeBtn.textContent = `赞 (${data.new_count})`;
// 可能更新按钮样式
} else {
alert('点赞文章出错: ' + data.error);
}
})
.catch(error => console.error('错误:', error));
});
// 获取 CSRF cookie 的简单方法(更稳健的版本请参阅 Django 文档)
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
</script>
  1. View (views.py):
import json
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.shortcuts import get_object_or_404
from .models import Post
@require_POST # 确保此视图仅接受 POST 请求
def like_post_view(request):
try:
data = json.loads(request.body)
post_id = data.get('post_id')
post = get_object_or_404(Post, pk=post_id)
# 添加逻辑以增加点赞计数(考虑原子性)
post.like_count += 1
post.save(update_fields=['like_count'])
return JsonResponse({'success': True, 'new_count': post.like_count})
except Exception as e:
return JsonResponse({'success': False, 'error': str(e)}, status=400)
  1. URL (urls.py):
from django.urls import path
from . import views
urlpatterns = [
# ... 其他 urls
path('like_post/', views.like_post_view, name='like_post'),
]

对于复杂的 API,请考虑使用 Django REST Framework (DRF),它提供了 Serializer、ViewSet 和 Router 来构建健壮的 REST API。