引言:为啥要给网站装上“门锁”?
想象一下,你呕心沥血建了个超酷的线上小窝(网站),里面有你的私密日记、珍藏手办,结果发现连隔壁二大爷都能推门就进,随手顺走你的“精神食粮”……这能忍?
当然不能!所以,是时候给你的网站装上第一道“门锁”——用户登录系统。
别一听“系统”俩字就头大,觉得是那些年薪百万的架构师才能玩转的东西。今天,我就用Django这个“魔法杖”,带你从零开始,亲手打造一个既安全又好看的登录功能。过程就像搭乐高,简单、有趣,还特别有成就感!准备好了吗?我们的“造门”之旅,现在发车!
第一幕:开工前的“寻宝图”——项目准备
在开始敲代码之前,我们得先确认“藏宝图”在手。假设你已经安装好了Python和Django,并且创建了一个Django项目,名叫 my_awesome_site,里面有个叫 accounts 的App(专门负责用户相关事务)。
检查清单:
- 项目结构:你的文件目录应该大致长这样:
my_awesome_site/
│ manage.py
│
└───my_awesome_site/
│ │ settings.py
│ │ urls.py
│ │ ...
│
└───accounts/ # 这就是我们今天的主角App
│ models.py
│ views.py
│ urls.py
│ ...
└───templates/
└───accounts/
login.html # 我们待会儿要创建的登录页面
- App注册:确保你的
accountsApp已经在settings.py的INSTALLED_APPS里报了到。
# my_awesome_site/settings.py
INSTALLED_APPS = [
# ... 其他自带的App
'django.contrib.auth', # Django自带的认证系统,核心!
'django.contrib.contenttypes',
'accounts', # 我们的App,必须加上!
]
- 数据库迁移:Django自带了一个强大的用户模型(User Model),我们直接拿来用就好。在终端运行:
python manage.py migrate
这行命令就像是在给你的数据库“打地基”,Django自带的用户表等结构就会被创建出来。
搞定! 我们的工具箱和蓝图都齐活了,接下来开始施展真正的技术吧!
第二幕:白嫖是王道!Django自带的“神级用户模型”
很多新手会犯一个错误:一上来就自己吭哧吭哧写一个User模型。Stop!千万别!
Django早就为你准备好了一个满配的、经过千锤百炼的 User 模型,它住在 django.contrib.auth.models 里。这个模型有多牛呢?它自带了:
- 用户名、邮箱、密码(自动加密存储)
- 名字、姓氏
- 权限和用户组管理
- 是否是超级用户、是否是活跃用户等一堆实用字段。
我们的口号是:能白嫖,绝不自造!
这个现成的模型,就是我们实现登录功能的“核动力引擎”。在 views.py 里,我们首先需要把它请出来:
from django.contrib.auth.models import User
当然,更重要的是Django配套的认证(Authentication)框架,它提供了登录、登出、权限校验等一系列功能。
from django.contrib.auth import authenticate, login, logout
看,帮手我们都请到位了!
第三幕:C位担当!编写“登录视图”的魔法逻辑
视图(View)是Django处理请求和返回响应的“大脑”。登录功能的核心逻辑,就写在这里。
打开 accounts/views.py,我们要开始“施法”了:
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib import messages
def user_login(request):
# 如果用户已经登录了,还点登录链接,就把他送回家(比如首页)
if request.user.is_authenticated:
return redirect('home') # 假设你有个叫 'home' 的URL
# 判断用户是不是通过表单提交了数据(也就是点了登录按钮)
if request.method == 'POST':
# 从表单里拿到用户输入的用户名和密码
username = request.POST.get('username')
password = request.POST.get('password')
# 魔法第一步:认证用户
# authenticate() 函数会拿着用户名和密码去数据库里核对
# 如果对了,就返回一个user对象;如果不对,就返回None
user = authenticate(request, username=username, password=password)
# 如果user不是None,说明认证成功!
if user is not None:
# 魔法第二步:执行登录操作!
# login() 函数会在服务器端开启一个Session(会话),并把Session ID塞给用户的浏览器(通过Cookie)
# 这样,用户接下来的操作,服务器就知道“哦,是你啊!”
login(request, user)
# 登录成功后,可以给用户一个闪亮的提示消息
messages.success(request, f'欢迎回来,{username}!')
# 然后跳转到成功后的页面,比如首页
return redirect('home')
else:
# 如果认证失败,就给用户一个错误提示
messages.error(request, '用户名或密码错误,请重试。')
# 注意:这里不能redirect,否则消息就没了,要重新渲染登录页面并保留表单数据
return render(request, 'accounts/login.html')
# 如果请求不是POST(比如是GET),说明用户只是想来要一个空的登录页面
else:
return render(request, 'accounts/login.html')
代码逻辑精讲:
request.method == 'POST':这是区分用户是“来要页面”还是“来提交数据”的关键。authenticate():这是Django的“保安”,它只负责核对身份证(用户名)和口令(密码)是否匹配,但不负责放行。login(request, user):这才是真正的“开门”动作。它建立了本次浏览的会话,让用户保持登录状态。
看,核心逻辑就这么清晰!是不是感觉Django已经把最难的活儿都干了?
第四幕:颜值即正义!设计“登录页面”的化妆术
大脑(视图)有了,还得有个漂亮的脸蛋(模板)给用户看。我们在 accounts/templates/accounts/login.html 创建一个HTML文件。
这里我们用Django自带的表单功能稍微美化一下,但为了极致的控制和低AIGC痕迹,我们手写一个简单的表单:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>欢迎登录 - 我的酷站</title>
<!-- 引入Bootstrap让页面瞬间变美 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h3 class="card-title text-center mb-4">🔐 兄弟,请刷卡登录</h3>
<!-- 这里是显示Django消息的地方,比如错误提示 -->
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
<!-- 登录表单开始 -->
<form method="post" action="{% url 'login' %}">
<!-- 千万别忘了这行!Django用于防护CSRF攻击的令牌 -->
{% csrf_token %}
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<input type="text" class="form-control" id="username" name="username" placeholder="请输入你的大名" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password" name="password" placeholder="请输入神秘密码" required>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">🚀 一键登录!</button>
</div>
</form>
<!-- 表单结束 -->
<hr>
<p class="text-muted text-center">还没账号?<a href="#">赶紧注册一个吧!</a></p>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
这个页面虽然简单,但该有的都有:响应式布局、友好的提示、错误消息展示,以及最重要的——那个把数据提交给大脑(视图)的 form 表单。
第五幕:穿针引线!配置URL路由的“交通指挥员”
现在,大脑(视图)和脸蛋(模板)都有了,但用户怎么找到它们呢?这就需要URL配置来当“交通指挥员”了。
首先,在项目的总路由 my_awesome_site/urls.py 里,把关于用户的所有请求,都分发给 accounts 这个App去处理。
# my_awesome_site/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')), # 所有以/accounts/开头的链接,都去找accountsApp
]
然后,在 accounts App下创建一个 urls.py 文件,并定义登录页面的具体路径:
# accounts/urls.py
from django.urls import path
from . import views
app_name = 'accounts' # 给这个App的URL起个命名空间,防止重名
urlpatterns = [
path('login/', views.user_login, name='login'), # 路径是 /accounts/login/,对应user_login视图,名叫'login'
]
这样一来,当用户访问 http://127.0.0.1:8000/accounts/login/ 时,Django就能准确地找到 user_login 这个视图函数来处理请求了。
第六幕:灵魂拷问!Session与Cookie是如何“狼狈为奸”记住你的?
你可能一直有个疑问:为什么登录一次后,浏览器就知道我是谁了?这背后就是 Session 和 Cookie 这对“好兄弟”在搞事情。
- Cookie:是服务器发给浏览器的一小段文本信息(存在你的电脑上)。下次浏览器再访问同一服务器时,会自动带上这个Cookie。它就像你去游乐园时,工作人员在你手上盖的那个荧光章。
- Session:是存储在服务器端的数据,用来记录用户的状态。它就像游乐园的中央系统,记录着你手上这个荧光章对应的票是成人票还是儿童票,玩了哪些项目。
登录流程的绝妙配合:
- 当你登录成功时,Django的
login()函数会做两件事:
-
- 在服务器端创建一个Session,里面存上你的用户ID等信息。
- 给这个Session生成一个唯一的ID(Session ID)。
- 在返回给浏览器的响应中,带上一个名为
sessionid的Cookie,它的值就是这个Session ID。
- 你的浏览器收到响应后,就把这个
sessionid的Cookie保存起来。 - 接下来,你访问网站的任何一个页面,浏览器都会自动在请求头里带上这个
sessionidCookie。 - 服务器收到请求,一看Cookie里有
sessionid,就去Session库里查找,找到后就知道:“哦,原来是用户ID为123的老张啊!”于是,request.user这个对象就被自动设置成了老张。
所以,request.user.is_authenticated 才能用来判断用户是否登录。这一切,Django都为你自动化了,你几乎无需手动操作它们!
完整示例代码汇总 & 避坑指南
避坑指南(血泪经验):
csrf_token忘了写:这是最常见的错误!如果你的表单是POST请求,模板里必须写{% csrf_token %},否则Django会直接返回403错误,认为你在发动CSRF攻击。- 表单字段名不对:在视图里用
request.POST.get('username')获取数据,这里的'username'必须和模板里<input name="username">的name属性完全一致! - 认证失败后直接Redirect:如果认证失败,应该用
render重新渲染页面并显示错误信息。如果用redirect,页面一刷新,错误信息就没了,用户体验极差。 - 没处理已登录用户:在登录视图开头加一个判断,如果用户已经登录,就直接跳走,避免重复登录。
结语:你的“门神”已就位!
恭喜你!跟着这篇攻略,你已经成功地为你的Django网站请来了一位强大的“门神”。
我们回顾一下核心步骤:利用Django自带的User模型 → 编写认证和登录逻辑的视图 → 创建用户友好的登录模板 → 配置URL让一切连通 → 理解背后Session/Cookie的默契配合。
整个过程,我们几乎没有造轮子,全是站在Django这个巨人的肩膀上。这就是Django框架的魅力——它把复杂的安全问题封装成简单的函数,让我们能更专注于业务逻辑和用户体验。
现在,你的网站再也不是谁都能进的“公共广场”了。快去启动服务器 (python manage.py runserver),访问 /accounts/login/,测试一下你的劳动成果吧!
下一步,你还可以为这个系统添加上用户注册、密码重置、邮件验证等功能,让你的用户系统变得更加完善和强大。但无论如何,今天这扇“登录之门”,已经是你征服Django世界的第一步,也是最坚实的一步!

被折叠的 条评论
为什么被折叠?



