Python 现代开发学习笔记

(十四)注册、登录与退出交给用户系统

1. 账号表单与密码摘要

SignupForm 继承 Django 的 UserCreationForm,检查用户名、两次密码和项目配置的密码规则。form.save() 保存用户并生成密码摘要,页面视图只连接表单和跳转:

# 项目文件:reading_project/src/library/views.py
import csv
import json

from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.core.exceptions import BadRequest
from django.core.paginator import Paginator
from django.db import IntegrityError, transaction
from django.http import HttpResponse, JsonResponse
from django.shortcuts import redirect, render
from django.views.decorators.http import require_POST

from .forms import BookForm, SignupForm
from .models import Book
from .service import owned_book, public_book, save_book


def signup(request):
    # 空 POST 也属于一次提交;只有字段和密码规则都通过才创建用户。
    form = SignupForm(request.POST if request.method == "POST" else None)
    if request.method == "POST" and form.is_valid():
        form.save()
        messages.success(request, "注册成功,请登录")
        return redirect("login")
    return render(
        request,
        "registration/signup.html",
        {"form": form},
        status=422 if form.is_bound else 200,
    )

文件顶部导入了后续书籍视图共用的工具:render 生成页面响应,redirect 生成跳转,messages 暂存提示,login_required 与 permission_required 检查身份和操作权限。数据库与分页工具会在后面的具体动作中使用。

这份页面继承 base.html 的导航骨架,{% include '_fields.html' %} 插入表单控件,{% csrf_token %} 生成隐藏令牌。前两种组合方式沿用上一章的模板思路;隐藏令牌由 Django 生成与检查,下一节跟踪它的实际值。完整骨架和字段片段在(十七)展开。

<!-- 项目文件:reading_project/src/library/templates/registration/signup.html -->
{% extends 'base.html' %}
{% block title %}注册账号{% endblock %}
{% block content %}<section class="panel auth-panel"><h1>注册账号</h1>
  <form method="post">{% csrf_token %}{% include '_fields.html' %}<button type="submit">注册</button></form>
</section>{% endblock %}

2. 登录恢复到目标页面

LoginView 显示 registration/login.html,POST 时使用认证表单核对密码。成功后建立用户会话,再按 next 或默认首页跳转。login_required 把匿名页面请求送到 /accounts/login/?next=...,用户登录后可以回到刚才想打开的页面。

<!-- 项目文件:reading_project/src/library/templates/registration/login.html -->
{% extends 'base.html' %}
{% block title %}登录书架{% endblock %}
{% block content %}<section class="panel auth-panel">
  <p class="eyebrow">继续你的阅读记录</p><h1>登录书架</h1>
  <form method="post">{% csrf_token %}{% include '_fields.html' %}
    {% if next %}<input type="hidden" name="next" value="{{ next }}">{% endif %}
    <button type="submit">登录</button>
  </form><p class="muted"><a href="{% url 'signup' %}">注册一个自己的账号</a></p>
</section>{% endblock %}

next 的最终跳转地址由登录视图检查,外部地址不能直接取代本站跳转。页面中的隐藏字段经过模板转义;请求值不是未经判断就被当成任意跳转目标。

LogoutView 使用 POST,结束当前会话再跳到配置的登录页。默认用户系统的接口可查 Django 认证系统。

匿名访问书架先跳登录并携带 next,认证表单核对密码后建立数据库会话,再跳回本站目标,退出 POST 删除会话

笔记正文与全部题解 · Ctrl / ⌘ K