【Django】-7- 实现注册功能

发布于:2025-08-04 ⋅ 阅读:(14) ⋅ 点赞:(0)

🚀 Django 注册功能实现全流程(分 4 步)

按照 “设计 UI → 创建视图 → 添加路由 → 前后端对接” 的四个步骤,让用户在 accounts/register/ 页面完成注册~

  1. 设计 UI: register.html 模板
  2. 创建视图
  3. 添加路由
  4. 前后端对接

第二步:创建视图(直接返回 HTML 文件)

def register(request):
    # 1. 打开并读取 register.html 的内容
    html = open('register.html', encoding="utf-8").read()
    # 2. 把 HTML 内容返回给用户
    return HttpResponse(html)

把 register.html 放到 App 的 templates 目录 ,用 Django 模板加载(更规范):

from django.shortcuts import render

def register(request):
    # Django 会自动去 templates 目录找 register.html
    return render(request, 'register.html')

第三步:添加路由(让 accounts/register 能访问)

项目主路由 urls.py :

from django.urls import path, include

urlpatterns = [
    # ... 其他路由 ...
    path("accounts/", include("beifan.accounts_urls")),
]

  1. 路径清晰:注册页面的路径是 accounts/register/ ,别人一看就知道是 “账号相关功能”,和业务页面(beifan/xxx )区分开。
  2. 路由解耦:把 “账号相关路由” 放到单独的 accounts_urls.py ,让 beifan/urls.py 专注处理业务路由,代码更清晰。
  3. 可扩展:后续想加登录、登出、密码重置功能,直接在 accounts_urls.py 里加路由,维护更方便。

 

🎭 Django 路由 “接力赛” 

urlpatterns = [
    # ... 其他路由 ...
    path("accounts/", include("django.contrib.auth.urls")),
    path("accounts/", include("beifan.accounts_urls")),
]

Django 的匹配逻辑

  1. 当用户访问 accounts/xxx 时,Django 先找 第一个 accounts/ 路由(即 django.contrib.auth.urls )。
  2. 如果 django.contrib.auth.urls 里有匹配的子路由(比如 accounts/login ),就用它的视图。
  3. 如果 没找到 ,才会找 第二个 accounts/ 路由(即 beifan.accounts_urls )。

django.contrib.auth.urls 里有啥?

Django 自带的 django.contrib.auth.urls ,默认包含这些常用路由:

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
    path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
    path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
    path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

场景 1:访问 accounts/login/

  1. 用户访问 http://127.0.0.1:8000/accounts/login/
  2. Django 先检查第一个 accounts/ 路由(django.contrib.auth.urls )→ 发现有 login/ 路由 → 调用 Django 自带的登录视图 → 返回登录页面。

场景 2:访问 accounts/register/

  1. 用户访问 http://127.0.0.1:8000/accounts/register/
  2. Django 先检查第一个 accounts/ 路由(django.contrib.auth.urls )→ 发现 没有 register/ 路由 → 接力给第二个 accounts/ 路由(beifan.accounts_urls )。
  3. beifan.accounts_urls 里有 register/ 路由 → 调用你的 register 视图 → 返回注册页面。

接下来需要在 beifan/accounts_urls.py 里配置子路由

from django.urls import path
from beifan import views  # 导入 beifan 的 views

urlpatterns = [
    # 当用户访问 accounts/register 时,调用 register 视图
    path('register', views.register, name='register'),
]

路由别名的超能力(为什么需要 name )

1. 模板里用别名生成 URL

在 HTML 模板里,不用写死 URL :

<!--  BAD :硬写 URL ,如果路径变了要改所有模板 -->
<a href="/accounts/register">去注册</a>

<!--  GOOD :用别名,路径变了只改路由配置 -->
<a href="{% url 'register' %}">去注册</a>

  • 作用:如果以后把 register 的 URL 改成 accounts/signup ,只要在路由里改 path('signup', ...) ,模板里的 {% url 'register' %} 会自动变成新路径,不用挨个改模板!

2. 视图里用别名跳转

在视图函数里,跳转页面时用别名:

from django.shortcuts import redirect
from django.urls import reverse

def login(request):
    # 登录成功后,跳转到注册页(用别名)
    return redirect(reverse('register'))

  • 作用:和模板同理,路由路径变了,只要别名不变,reverse('register') 会自动生成新路径,不用改视图里的跳转逻辑~

四、🚀 前后端对接!Axios 请求 & Django 交互 

核心流程

前端(浏览器)用 Axios 发请求 → 后端(Django)接收并处理 → 返回响应 → 前端处理响应 / 错误~

1. 引入 Axios 库

<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js"></script>

  • 作用:加载 Axios 库,让前端能发 HTTP 请求(比如 POST、GET )。
  • 类比:给前端装一个 “请求小飞机” ,用来给后端送信(数据)~

2. Axios 发 POST 请求

axios({
    method: "post",  // 请求方法:POST
    url: "http://127.0.0.1:8000/accounts/register",  // 后端接口地址
    data: formData,  // 要发的数据(比如注册表单)
}).then(function (response) {  // 请求成功
    alert(response.data.msg);
}).catch(function (error) {  // 请求失败
    alert(error.response.data.msg);
})
① method: "post" → 请求方法
  • 作用:告诉后端 “我要提交数据”(比如注册表单)。
  • 类比:给 “请求小飞机” 设置飞行模式 → “投递模式”(送数据给后端)。

② url: "http://127.0.0.1:8000/accounts/register" → 后端地址
  • 作用:指定后端的 “收件地址” ,告诉 Axios 把请求发给 Django 的 accounts/register 接口。
  • 类比:在 “请求小飞机” 上写清楚收件地址 → 飞到 Django 后端的 accounts/register 门口~

③ data: formData → 要发的数据
  • 作用:把前端表单数据(比如用户名、密码)打包成 formData ,发给后端。
  • 类比:把注册表单写成 “信件”,放进 “请求小飞机” 的货舱~

④ .then(...) → 请求成功的回调
  • 作用:如果后端成功收到并处理请求,执行这里的代码。
  • response.data.msg:假设后端返回的数据里有 msg 字段(比如 “注册成功”),用 alert 弹提示。
  • 类比:“请求小飞机” 成功送到信件,后端回信里有 msg → 前端弹出回信内容~

⑤ .catch(...) → 请求失败的回调
  • 作用:如果请求失败(比如网络问题、后端报错),执行这里的代码。
  • error.response.data.msg:获取后端返回的错误信息(如果有),用 alert 弹提示。
  • 类比:“请求小飞机” 没送到,或者后端回信说 “操作失败” → 前端弹出错误原因~

后端需要做什么?(Django 部分)

接收并处理 POST 请求

在 beifan/views.py 的 register 视图里,处理前端发的 POST 数据:

import json
from django.http import JsonResponse, HttpResponse
from django.contrib.auth import login, User  # 导入 User 模型和登录函数

def register(request):
    """
    处理用户注册请求的视图函数,支持 GET 展示页面、POST 提交注册逻辑
    """
    # 1. 处理 GET 请求:返回注册页面 HTML
    if request.method == 'GET':
        # 读取 HTML 文件并返回
        html = open('register.html', encoding="utf-8").read()
        return HttpResponse(html, status=200)

    # 2. 处理 POST 请求:校验数据并完成注册
    elif request.method == 'POST':
        # 解析请求体的 JSON 数据
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({
                "code": -10,
                "msg": "请求体不是合法的 JSON 格式"
            }, status=400)

        # 3. 校验必填字段(email、username、password、password_confirm)
        key_list = ['email', 'username', 'password', 'password_confirm']
        for key in key_list:
            if len(data.get(key, "")) < 1:
                return JsonResponse({
                    "code": -1,
                    "msg": f"{key} 不能为空"
                }, status=422)

        # 4. 校验两次密码是否一致
        if data['password'] != data['password_confirm']:
            return JsonResponse({
                "code": -2,
                "msg": "两次密码输入不一致"
            }, status=422)

        # 5. 校验密码长度(不少于 6 位)
        if len(data['password']) < 6:
            return JsonResponse({
                "code": -3,
                "msg": "密码长度不能少于 6 位"
            }, status=422)

        # 6. 校验用户名是否已存在
        user_list = User.objects.filter(username=data['username'])
        if len(user_list) > 0:
            return JsonResponse({
                "code": -4,
                "msg": "该用户已存在"
            }, status=400)

        # 7. 所有校验通过,创建新用户
        try:
            new_user = User.objects.create_user(
                username=data['username'],
                email=data['email'],
                password=data['password'],
            )
        except Exception as e:
            return JsonResponse({
                "code": -5,
                "msg": f"创建用户失败:{str(e)}"
            }, status=500)

        # 8. 自动登录(注册成功后直接登录)
        login(request, new_user)

        # 9. 返回注册成功响应
        return JsonResponse({
            "code": 0,
            "msg": "注册成功"
        }, status=201)

    # 3. 处理不支持的请求方法
    else:
        return JsonResponse({
            "code": -99,
            "msg": "不支持的请求方法"
        }, status=405)

五、🎭 详解后端处理视图 

整体功能 🌟

这个 register 函数就像一个 “注册小管家” ,能同时处理两种请求:

  • 👉 GET 请求:给前端返回注册页面(让用户看到输入框)
  • 👉 POST 请求:接收前端发来的注册数据,验证、创建用户,最后告诉 “成功 / 失败”

处理 GET 请求:给前端 “展示注册页面” 📄

if request.method == 'GET':
    # 读取 HTML 文件并返回
    html = open('register.html', encoding="utf-8").read()
    return HttpResponse(html, status=200)
场景再现:

前端用户在浏览器输入 accounts/register → 发 GET 请求给后端~

  • 小管家说:“哦,是来要注册页面的呀!”
  • 打开 register.html 文件,把内容读出来 → 用 HttpResponse 打包成 “网页快递” 发给前端~
  • 前端用户就能看到注册表单(输入用户名、密码的页面)啦!

处理 POST 请求:接收前端的注册数据并处理 📦

当用户填完表单点 “注册”,前端用 Axios 发 POST 请求,把数据发给后端~
小管家开始 “三步走”:解析数据 → 校验数据 → 创建用户~

① 第一步:解析前端发来的 JSON 数据 📦→📝
try:
    data = json.loads(request.body)
except json.JSONDecodeError:
    return JsonResponse({
        "code": -10,
        "msg": "请求体不是合法的 JSON 格式"
    }, status=400)

  • request.body:前端用 Axios 发的 data 数据(比如 {username: "小明", password: "123456"} ),藏在这里~
  • json.loads(...):把 JSON 字符串转换成 Python 字典 data ,方便后续操作~
  • 万一前端发的不是 JSON(比如格式错了)→ 小管家返回 code=-10 + “格式不对”,前端 catch 到后弹窗提示用户~

② 第二步:校验数据(看看用户填的对不对) ✅❌

小管家化身 “安检员”,一个个检查数据:

🔍 检查必填项(email、username、password、password_confirm)
key_list = ['email', 'username', 'password', 'password_confirm']
for key in key_list:
    if len(data.get(key, "")) < 1:
        return JsonResponse({
            "code": -1,
            "msg": f"{key} 不能为空"
        }, status=422)

  • 场景:如果用户没填 username → 小管家返回 code=-1 + “username 不能为空”~
  • 前端收到后,弹窗提示用户 “用户名不能为空”,超贴心!

🔍 检查两次密码是否一致
if data['password'] != data['password_confirm']:
    return JsonResponse({
        "code": -2,
        "msg": "两次密码输入不一致"
    }, status=422)

  • 场景:用户第一次输 123456 ,第二次输 1234567 → 小管家返回 code=-2 + “两次密码不一样”~

🔍 检查密码长度(不少于 6 位)
if len(data['password']) < 6:
    return JsonResponse({
        "code": -3,
        "msg": "密码长度不能少于 6 位"
    }, status=422)

  • 场景:用户密码输 123 → 小管家返回 code=-3 + “密码太短啦”~

🔍 检查用户名是否已存在
user_list = User.objects.filter(username=data['username'])
if len(user_list) > 0:
    return JsonResponse({
        "code": -4,
        "msg": "该用户已存在"
    }, status=400)

  • 小管家去数据库 “查户口”:有没有叫这个用户名的用户?
  • 有的话 → 返回 code=-4 + “用户名被抢啦”~

③ 第三步:所有检查通过!创建用户并自动登录 🎉
try:
    new_user = User.objects.create_user(
        username=data['username'],
        email=data['email'],
        password=data['password'],
    )
except Exception as e:
    return JsonResponse({
        "code": -5,
        "msg": f"创建用户失败:{str(e)}"
    }, status=500)

# 自动登录
login(request, new_user)

# 返回成功响应
return JsonResponse({
    "code": 0,
    "msg": "注册成功"
}, status=201)

  • User.objects.create_user(...):Django 自带的 “创建用户魔法”,会自动把密码加密(不会明文存!)~
  • 万一创建失败(比如数据库出错)→ 返回 code=-5 + 错误原因~
  • 成功的话 → 调用 login(request, new_user) :自动登录!用户不用再手动输账号密码~
  • 最后返回 code=0 + “注册成功” → 前端 then 里弹窗庆祝,比如 “恭喜注册成功!”

request 里装了啥?

当用户注册时,前端发的是 POST 请求,所以 request 里确实包含 POST 相关的信息:

  • request.method → 等于 "POST"(告诉后端这是个提交数据的请求)
  • request.POST 或 request.body → 装着用户填的注册数据(用户名、密码等)

但 request 里还有更多 “宝贝”:

  • request.user → 当前用户(注册前是匿名用户,登录后会变成 new_user
  • request.session → 用来存储会话信息的 “小本本”(login 函数主要用它来记录登录状态)
  • request.META → 浏览器信息、IP 地址等 “隐藏信息”

login 函数拿了 request 会做什么?

login(request, new_user) 拿到这个 “快递箱” 后,主要干这两件事:

  1. 在 request.session 里记笔记
    给 new_user 生成一个唯一的 “登录凭证”(类似 sessionid),写进 request.session 里,相当于:

    request.session['user_id'] = new_user.id  # 偷偷偷偷记下用户ID
    

  2. 更新 request.user
    把 request.user 从 “匿名用户” 换成 new_user,这样后续在视图里用 request.user 就能直接拿到登录用户啦~

处理不支持的请求方法(比如 PUT、DELETE) 🚫

else:
    return JsonResponse({
        "code": -99,
        "msg": "不支持的请求方法"
    }, status=405)

  • 如果前端发了个奇怪的请求方法(比如 PUT )→ 小管家说 “我不支持哦”,返回 code=-99

前后端 “对话” 小剧场 🎬

场景:用户注册成功

  1. 前端(Axios):
    “小管家,我发 POST 请求啦,数据是 {username: "小明", password: "123456", ...} ,请查收!”

  2. 后端小管家:

    • 解析数据 → 检查必填项 → 密码一致 → 密码够长 → 用户名没重复 → 全部通过!
    • 创建用户 “小明” → 自动登录 → 回复:{"code":0, "msg":"注册成功"}
  3. 前端:
    收到 code=0 → 弹窗 “注册成功!” → 跳转到首页~

场景:用户密码太短

  1. 前端:“小管家,数据是 {password: "123", ...} ~”

  2. 后端小管家:
    检查发现密码长度 3 < 6 → 回复:{"code":-3, "msg":"密码长度不能少于 6 位"}

  3. 前端:
    收到 code=-3 → 弹窗 “密码太短啦,至少要 6 位哦~” → 让用户重新输入~

代码超贴心的点 ❤️

  1. 错误码清晰:每个错误都有专属 code (比如 -1 空字段、-2 密码不一致),前端能根据 code 做不同处理(比如给输入框标红)。
  2. 自动加密密码create_user 会自动加密密码,数据库里看不到明文,超安全!
  3. 自动登录:注册成功后直接登录,用户体验 up up ~
  4. 支持 GET/POST:一个函数搞定 “展示页面” 和 “处理注册”,不用分开写~

六、🌈 登录成功后跳转到业务页面!前端重定向 

方法 1:用 window.location.href 直接跳转 🚀

这是最直接的方式,就像在浏览器地址栏输入新网址一样~

代码示例(配合 Axios 成功回调):

// 登录请求的 Axios 代码
axios({
  method: "post",
  url: "http://127.0.0.1:8000/accounts/login",
  data: {
    username: "小明",
    password: "123456"
  }
}).then(function(response) {
  // 登录成功(后端返回 code=0 )
  if (response.data.code === 0) {
    // 跳转到业务页面(比如 /beifan/index )
    window.location.href = "/beifan/index"; 
    // 也可以写全路径:http://127.0.0.1:8000/beifan/index
  }
}).catch(function(error) {
  // 登录失败,弹窗提示
  alert(error.response.data.msg);
});

原理:

window.location.href 是浏览器的 “地址栏魔法”,赋值新路径后,页面会立刻跳转到该地址~
类比:你告诉浏览器 “别待在登录页了,快去业务页面!”,浏览器就听话跳转啦~

方法 2:用 window.location.replace 跳转(更干净)🧼

和方法 1 类似,但会 “删掉” 登录页的历史记录,用户点 “后退” 不会回到登录页~

代码示例:

.then(function(response) {
  if (response.data.code === 0) {
    // 跳转到业务页面,且保留登录页历史
    window.location.replace("/beifan/index"); 
  }
})
适合场景:

登录后不希望用户后退回到登录页(比如已登录状态下不允许再访问登录页),用这个更合适~

方法 3:如果用了前端框架(如 Vue/React)🧩

如果你的用了 Vue 或 React ,可以用框架自带的路由工具跳转(更优雅雅~)

Vue 示例(用 Vue Router):

// 先导入路由
import { useRouter } from 'vue-router';
const router = useRouter();

// 登录成功后
.then(function(response) {
  if (response.data.code === 0) {
    // 跳转到业务页面(路由配置的 path )
    router.push("/beifan/index"); 
  }
})

React 示例(用 React-router-dom):

// 先导入 useNavigate
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();

// 登录成功后
.then(function(response) {
  if (response.data.code === 0) {
    // 跳转到业务页面
    navigate("/beifan/index"); 
  }
})

小剧场:登录端跳转全过程 🎭

  1. 用户填完登录表单,点击 “登录” → 前端发 Axios 请求给后端。
  2. 后端验证成功,返回 {"code":0, "msg":"登录成功"} 。
  3. 前端 then 回调里:
    • 看到 code=0 → 执行 window.location.href = "/beifan/index" 。
    • 浏览器地址栏瞬间变成 http://127.0.0.1:8000/beifan/index → 页面面跳转到业务页面~
  4. 用户开心地在业务务页面操作啦!


网站公告

今日签到

点亮在社区的每一天
去签到