@login_required
是 Django 提供的一个装饰器 (decorator),用于保护视图函数,确保只有已登录的用户才能访问该视图。它是 Django 认证系统的核心组件之一,提供了简单而强大的访问控制功能。
环境准备
安装 Django
pip install django
项目创建步骤
1. 创建 Django 项目
django-admin startproject myproject
cd myproject
2. 创建应用
python manage.py startapp bookapp
项目结构
3. 配置项目 (settings.py)
在myproject/settings.py
中添加以下配置:
INSTALLED_APPS = [
# ...其他应用
'bookapp',
]
# 登录URL配置
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/books/'
LOGOUT_REDIRECT_URL = '/login/'
为什么要在 settings.py 中配置登录相关 URL?
Django 的认证系统设计了三个核心 URL 配置,用于处理认证流程中的页面跳转:
LOGIN_URL (
/login/
)- 作用:指定未登录用户访问受保护页面时的重定向目标
- 原理:当用户尝试访问被
@login_required
保护的视图时,Django 会检查用户认证状态,如果未登录,会自动重定向到该 URL
LOGIN_REDIRECT_URL (
/books/
)- 作用:指定用户登录成功后的默认跳转页面
- 应用场景:当用户直接访问登录页面并成功登录后,会跳转到该 URL
LOGOUT_REDIRECT_URL (
/login/
)- 作用:指定用户登出后的跳转页面
- 安全考虑:登出后重定向到登录页面是常见的安全实践
这些配置是全局设置,为整个项目提供一致的认证体验,避免在每个视图中重复定义相同的跳转逻辑。
4. 创建视图 (bookapp/views.py)
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import LoginView
from django.shortcuts import render
class CustomLoginView(LoginView):
template_name = 'login.html'
@login_required
def book_list(request):
# 示例书籍数据
books = [
{'id': 1, 'title': 'Django for Beginners', 'author': 'William S. Vincent'},
{'id': 2, 'title': 'Python Crash Course', 'author': 'Eric Matthes'},
{'id': 3, 'title': 'Two Scoops of Django', 'author': 'Daniel Roy Greenfeld'},
]
return render(request, 'book_list.html', {'books': books})
5. 配置 URL
myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('bookapp.urls')),
]
bookapp/urls.py
from django.urls import path
from django.contrib.auth.views import LogoutView
from . import views
urlpatterns = [
path('login/', views.CustomLoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
path('books/', views.book_list, name='book_list'),
]
6. 创建模板文件
创建模板目录
mkdir -p bookapp/templates
login.html
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<style>
.login-container { max-width: 400px; margin: 50px auto; padding: 20px; box-shadow: 0 0 10px #ccc; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; }
input { width: 100%; padding: 8px; box-sizing: border-box; }
button { background-color: #4CAF50; color: white; padding: 10px 15px; border: none; cursor: pointer; }
button:hover { background-color: #45a049; }
.error { color: red; margin-bottom: 15px; }
</style>
</head>
<body>
<div class="login-container">
<h2>Login</h2>
{% if form.errors %}
<div class="error">Your username and password didn't match. Please try again.</div>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="id_username">Username</label>
{{ form.username }}
</div>
<div class="form-group">
<label for="id_password">Password</label>
{{ form.password }}
</div>
<button type="submit">Login</button>
</form>
</div>
</body>
</html>
book_list.html
<!DOCTYPE html>
<html>
<head>
<title>Book List</title>
<style>
.container { max-width: 800px; margin: 0 auto; padding: 20px; }
.logout-link { text-align: right; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<div class="container">
<!-- 在book_list.html中替换原有的登出链接 -->
<div class="logout-link">
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button type="submit" style="background: none; border: none; color: blue; text-decoration: underline; cursor: pointer;">
Logout
</button>
</form>
</div>
<h1>Book List</h1>
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Author</th>
</tr>
{% for book in books %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
<td>{{ book.author }}</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
7.执行数据库迁移
ps:如果不执行数据库迁移,没有用户表,创建超级用户会失败
python manage.py migrate
8. 创建超级用户 (管理员)
python manage.py createsuperuser
9. 运行开发服务器
python manage.py runserver
实现效果:
http://127.0.0.1:8000/books
未登陆时,直接访问books,会跳转至登陆页
登陆成功后才能查看页面