一、🛡️ Django 鉴权 & 登录控制
Django 自带的鉴权系统(用户身份管理小管家)
鉴权系统能干啥?
Django 自带的鉴权系统,就像一个 “用户身份管家” ,帮你管好这些事儿:
功能 | 类比 |
---|---|
加密存储用户密码 | 把用户的 “秘密”(密码)锁进保险箱,存的时候自动加密~ |
登录表单 | 提供 “登录页面模板”(虽然需要自己改改样式,但基础功能有了)~ |
验证账号密码 | 检查用户输入的账号密码对不对,像 “门卫查身份证”~ |
验证是否登录 | 判断用户 “有没有带身份凭证”,没登录就不让进某些页面~ |
针对单用户的权限设置 | 给不同用户发 “权限卡片”(比如管理员能删数据,普通用户只能看)~ |
启用鉴权系统的条件(配置检查)
要让鉴权系统工作,项目里得有这两个 “开关”(在 settings.py
):
① INSTALLED_APPS
里要有这俩
INSTALLED_APPS = [..."django.contrib.auth", # 鉴权核心功能"django.contrib.contenttypes", # 辅助管理权限...
]
- 类比:给 “身份管家” 开通 “系统权限”,让它能在项目里工作~
② MIDDLEWARE
里要有这俩中间件
MIDDLEWARE = [..."django.contrib.sessions.middleware.SessionMiddleware", # 管理用户会话(登录状态)"django.contrib.auth.middleware.AuthenticationMiddleware", # 管理用户身份验证...
]
SessionMiddleware
:给用户发 “会话饼干”(记录登录状态)~AuthenticationMiddleware
:检查用户的 “身份饼干”,确认是否登录~- 类比:给 “身份管家” 配两个小助手,一个发饼干、一个查饼干~
禁止匿名访问(拦住没登录的人!)
场景
有些页面 / 功能(比如 “发布评论”),必须 登录后才能用 !如果匿名用户(没登录的人)访问,就 “拦住他”,让他先登录~
方法 1:手动判断(一步步拦)
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt # 演示用,实际要开CSRFdef submit(request):# request.user 是鉴权系统给的“用户身份对象”if not request.user.is_authenticated: # is_authenticated 是“检查是否登录”的小开关return HttpResponse("请登录后再发布", status=401)# 登录了就继续处理发布逻辑...
流程:
request.user
:鉴权系统把 “当前用户身份” 放到request
里,你可以直接用~request.user.is_authenticated
:判断用户 是否登录 (登录了返回True
,没登录返回False
)~- 如果没登录,返回 “请登录” 的提示(
status=401
表示 “未授权” )~
类比:
你:“小管家!看看这个用户有没有登录,没登录就拦住他!”
小管家:检查 request.user
的 “身份凭证”,没登录就说 “请先登录~”
方法 2:@login_required 装饰器(一键拦)
from django.contrib.auth.decorators import login_required@login_required
def submit(request):# 只有登录用户能进这个视图!...
流程:
@login_required
是 Django 提供的 “快捷拦人装饰器”~- 如果用户没登录,自动 跳转到登录页面 (需要在
settings.py
配置LOGIN_URL
)~
类比:
你给 “发布评论” 的门挂了一个 “登录才能进” 的魔法门牌(@login_required
)~
没登录的人想进门,直接被传送到 “登录页面”~
方法 2 的配置(让跳转生效)
在 settings.py
里加一行:
LOGIN_URL = '/login/' # 登录页面的 URL
- 这样,匿名用户访问被
@login_required
装饰的视图时,会自动跳转到/login/
~
Django 为了方便开发者处理用户的认证(登录、登出等)相关操作,内置了一套鉴权系统。
当你在项目的 URL 配置里,使用 include("django.contrib.auth.urls")
后,就相当于给项目 “接入” 了鉴权系统的一系列 URL (添加一个路由),其中就有 /accounts/login/
。
它的工作方式
视图函数:
当用户访问 /accounts/login/
时,Django 会找到鉴权系统里对应的视图函数( LoginView
,它是一个基于类的视图)。这个视图函数就像一个 “登录小助手”,负责处理用户登录的逻辑,比如验证用户输入的用户名和密码是否正确。
表单处理:
LoginView
会自动生成一个登录表单 ,包含用户名和密码的输入框。就好比小助手准备了一张 “登录申请表”,让用户填写信息。而且它还会对用户提交的表单数据进行校验,看看用户名和密码是不是匹配数据库里存储的用户信息。
登录状态管理:
如果用户输入的信息正确,LoginView
会通过 Django 的会话机制,给用户设置登录状态。这就像给用户发了一张 “小镇通行证”,用户后续访问需要登录才能查看的页面时,Django 就能通过这张 “通行证” 确认用户已经登录啦。
可定制性
虽然 /accounts/login/
是 Django 提供的,但它也是可以定制的哦。默认情况下它会去寻找 registration/login.html
这个模板文件来展示登录页面
总结(小剧场)
鉴权系统小剧场
你:“小管家!我需要管理用户登录、权限,你能帮我吗?”
小管家:“当然!我有加密密码、验证登录、管理权限的本事~ 不过你得在 settings.py
里开一下我的权限!”
禁止匿名访问小剧场
方法 1 场景:
用户(没登录)想访问 “发布评论” 页面~
小管家检查 request.user
,发现没登录 → 拦住:“请登录后再发布!”
方法 2 场景:
用户(没登录)想访问 “发布评论” 页面~
小管家看到门上挂了 @login_required
→ 直接把用户传送到登录页面:“先登录才能进!”
二、🚪 Django 登录页面实现
实现登录页面的流程(创建视图 + 路由)
1. 核心思路
Django 自带的鉴权系统,已经帮我们写好了 登录逻辑 (验证账号密码、设置登录状态),但 登录页面的模板需要自己提供 !
实现步骤就两步:
- 配路由(让
/accounts/login/
能找到 Django 自带的登录视图) - 写登录页面模板(告诉 Django 登录页面长啥样)
2. 配置路由(让请求找到 Django 登录视图)
from django.urls import path, includeurlpatterns = [# 包含 Django 自带的 auth 路由path("accounts/", include("django.contrib.auth.urls")),
]
include("django.contrib.auth.urls")
:这是 Django 提供的 “快捷路由”,里面包含了/accounts/login/
、/accounts/logout/
等常用登录、登出路由~- 类比:你给 “登录功能” 的请求,设置了一个 “自动导航”,让 Django 自带的登录视图处理请求~
访问效果
当你访问 http://127.0.0.1:8000/accounts/login/
时,Django 会找到自带的 LoginView
处理请求~
报错分析:TemplateDoesNotExist(模板找不到)
错误信息解读
TemplateDoesNotExist at /accounts/login/
registration/login.html
- Django 想找
registration/login.html
这个模板文件,但没找到~
为什么会找这个模板?
Django 自带的 LoginView
默认会去 templates/registration/login.html
找登录页面模板~
如果你的项目里没有这个文件,就会报错!
解决方法(给 Django 一个登录页面)
方法 1:自己写 login.html
模板
步骤 1:创建模板文件
在你的 App(比如 beifan
)目录下,创建这样的路径:
beifan/
└── templates/└── registration/└── login.html
template、registration是目录
- 路径必须是
templates/registration/login.html
,因为 Django 默认找这个位置~
步骤 2:写模板内容
在 login.html
里写登录页面的 HTML ,比如:
<!DOCTYPE html>
<html>
<head><title>登录</title>
</head>
<body><h1>欢迎登录</h1><form method="post">{% csrf_token %} <!-- 必须加,防止跨站攻击 -->{{ form.as_p }} <!-- 自动渲染登录表单 --><button type="submit">登录</button></form>
</body>
</html>
{{ form.as_p }}
:Django 会自动生成用户名、密码的输入框~
方法 2:复用 Django admin 的登录模板(偷懒版)
错误信息里的提示
{# beifan/templates/registration/login.html #}
{% extends "admin/login.html" %}
- 这行代码的意思是:“让登录页面继承 Django admin 的登录模板”,这样不用自己写样式~
步骤 1:创建模板文件
同样在 beifan/templates/registration/login.html
里写:
{% extends "admin/login.html" %}
{% extends "admin/login.html" %}
:表示 “我的登录页面,用 Django admin 的登录页面样式”~
步骤 2:确保 Django 能找到模板
在 settings.py
里,确保你的 App(beifan
)在 INSTALLED_APPS
里,并且模板配置正确:
INSTALLED_APPS = [...'beifan',...
]TEMPLATES = [{...'APP_DIRS': True, # 允许 Django 在 App 的 templates 目录找模板...},
]
步骤 3:检查模板路径
确保你的模板文件路径是:
beifan/
└── templates/└── registration/└── login.html
- 这样 Django 就能找到
registration/login.html
,继承admin/login.html
的样式~
总结(小剧场)
实现登录页小剧场
你:“Django 呀,我要做个登录页面,用户访问 /accounts/login/
时能登录~”
Django:“好呀!你配好路由(include('django.contrib.auth.urls')
),再给我一个 registration/login.html
模板,我就能显示登录页面啦!”
报错解决小剧场
你访问 /accounts/login/
,Django 大喊:“找不到 registration/login.html
模板!”
你:“哦~ 原来要自己创建这个文件!”
于是你在 beifan/templates/registration/
里创建 login.html
,要么自己写内容,要么继承 admin/login.html
,问题解决!
三、🎨 什么是Django 模板
模板就是 “HTML 半成品 + Django 魔法标记” ,让你能把 Python 数据(比如模型数据、变量)动态渲染到网页里~
模板是干啥的?
想象你要做 100 个 “用户订单详情页”,每个页面的结构一样(比如标题、表格),但数据不同(订单号、商品、价格)。
- 如果纯手写 HTML ,得复制 100 个文件,改数据 → 超麻烦!
- 用 Django 模板 → 写一个 “模板文件”(HTML 框架 + 动态标记),然后传不同数据进去,自动生成 100 个页面!
模板长啥样?(结构拆解)
1. 普通 HTML 部分(静态内容)
<!DOCTYPE html>
<html>
<head><title>我的页面</title>
</head>
<body><h1>欢迎来到我的网站!</h1><p>这是一段固定不变的文字~</p>
</body>
</html>
- 这部分和普通 HTML 一样,是静态内容(所有用户看到的都一样)~
2. Django 魔法标记(动态内容)
<!DOCTYPE html>
<html>
<head><title>{{ page_title }}</title> <!-- 动态标题 -->
</head>
<body><h1>欢迎 {{ user_name }} 来到我的网站!</h1> <!-- 动态用户名 --><p>你的订单号是:{{ order.id }}</p> <!-- 动态订单号 -->{% if user.is_vip %} <!-- 条件判断 --><p>你是 VIP 用户,享受专属优惠~</p>{% endif %}{% for product in products %} <!-- 循环遍历 --><li>{{ product.name }} - 价格:{{ product.price }}</li>{% endfor %}
</body>
</html>
{{ 变量 }}
:插入 Python 变量(比如page_title
、user_name
),把后端数据动态渲染到 HTML 里~
类比:在 HTML 里 “挖个坑”,让后端传数据填进来~{% 标签 %}
:控制逻辑(比如if
判断、for
循环 ),让 HTML 能根据后端数据 “动态变化”~
类比:给 HTML 加 “魔法指令”,让它能判断、循环,变聪明~
模板的作用(为啥需要它?)
1. 分离前后端
- 后端(Python)负责 “处理数据、业务逻辑”,前端(HTML)负责 “页面展示”~
- 模板就是 “桥梁”:让后端把数据传给前端,前端用 HTML + 魔法标记展示数据~
2. 复用代码
- 一个模板可以渲染 N 个页面(传不同数据就行),不用重复写 HTML 结构~
3. 动态交互
- 结合
{{ }}
和{% %}
,让页面能根据用户、数据的不同,展示不同内容~
模板的使用流程(小剧场)
1. 后端准备数据
from django.shortcuts import renderdef my_view(request):# 准备要传给模板的数据(字典形式)context = {'page_title': '我的动态页面','user_name': '北凡','order': {'id': 123},'user': {'is_vip': True},'products': [{'name': '魔法棒', 'price': 99},{'name': '仙女裙', 'price': 199},]}# 渲染模板,把 data 传给模板return render(request, 'my_template.html', context)
2. 前端模板 my_template.html
接收数据
<!DOCTYPE html>
<html>
<head><title>{{ page_title }}</title>
</head>
<body><h1>欢迎 {{ user_name }} 来到我的网站!</h1><p>你的订单号是:{{ order.id }}</p>{% if user.is_vip %}<p>你是 VIP 用户,享受专属优惠~</p>{% endif %}<h3>你的商品:</h3><ul>{% for product in products %}<li>{{ product.name }} - 价格:{{ product.price }}</li>{% endfor %}</ul>
</body>
</html>
3. 最终渲染的 HTML(用户看到的)
<!DOCTYPE html>
<html>
<head><title>我的动态页面</title>
</head>
<body><h1>欢迎 北凡 来到我的网站!</h1><p>你的订单号是:123</p><p>你是 VIP 用户,享受专属优惠~</p><h3>你的商品:</h3><ul><li>魔法棒 - 价格:99</li><li>仙女裙 - 价格:199</li></ul>
</body>
</html>
模板的存放位置
Django 会在这些地方找模板:
- 项目根目录的
templates
文件夹(适合全局模板) - 每个 App 目录下的
templates
文件夹(适合 App 专属模板)
比如你的 App 叫 beifan
,模板可以放在:
beifan/
└── templates/└── beifan/└── my_template.html
总结
模板就是 “会魔法的 HTML” ,通过 {{ }}
插变量、{% %}
写逻辑,让后端数据能动态渲染到前端页面里~
它让前后端分离更清晰、代码复用更方便、页面交互更灵活~ 掌握模板,就能做出 “千人千面” 的动态网页啦! 🎉