【Web应用开发笔记】Django笔记8:用户账户相关功能

前言

之前我们的"博客页面"项目已经有了如下功能:

  • 查看所有博客、博客具体页面
  • 新增博客
  • 编辑博客
  • 删除博客

这意味着我们的核心操作已经完成。但是还没有给用户提供账号相关功能

  • 注册
  • 登入
  • 登出

用户账户的这些功能如果自己实现显然会有很多可预见的问题,比如各种字符串校验、重名检查、安全校验 等等。

好在 Django 内置了相关的功能,我们可以直接使用。

1. 登入、登出

1.1 URL 配置

  • learn_django/urls.py
    • urlpatterns 列表中新增如下内容
python 复制代码
path("accounts/", include("django.contrib.auth.urls")),
  • 视图
    • 有了这个内置功能之后,我们不需要创建相关的视图了,因为 django.contrib.auth.urls 已经内置了完整的视图和模板。
    • 例如:
URL 路径 功能 内置视图
/accounts/login/ 登录页面 LoginView
/accounts/logout/ 登出功能 LogoutView
/accounts/password_change/ 修改密码 PasswordChangeView
/accounts/password_reset/ 重置密码 PasswordResetView
... ... ...
  • 模板来源:
    Django 内置了默认模板(位于 django/contrib/auth/templates/)
    如果你创建了 templates/registration/login.html,Django 会优先使用你的模板覆盖默认模板

1.2 settings.py

python 复制代码
# login
LOGIN_REDIRECT_URL = "home"
LOGOUT_REDIRECT_URL = "home"
配置项 作用 使用场景
LOGIN_REDIRECT_URL 登录成功后跳转的页面 用户提交登录表单验证通过后
LOGOUT_REDIRECT_URL 登出成功后跳转的页面 用户点击登出后

1.3 页面修改

1.3.1 登录页

  • templates/registration/login.html
html 复制代码
<!-- templates/registration/login.html -->
{% extends "base.html" %}

{% block content %}
<h2>Log In</h2>
<form method="post">{% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Log In</button>
</form>
{% endblock content %}

1.3.2 base.html

想象一下,假如我们希望在所有页面的最上面都可以看到如下信息:

  • 当前有没有登录
  • 是谁登录了
  • 没有登录的需要一个登录链接
  • 登录了的需要一个登出链接

满足以上要点的方法就是:

  • 所有页面:在 base.html 中
  • 条件选择:{% if user.is_authenticated %} ... {% else %} ... {% endif %}
  • 登入:{% url 'login' %}
  • 登出:{% url 'logout' %}

最终得到的页面如下:

  • templates/base.html
    • 关注这段:{% if user.is_authenticated %} 引导的逻辑
html 复制代码
<!-- templates/base.html -->
{% load static %}

<html>
    <head>
        <title>Django blog</title>
        <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400"
            rel="stylesheet">
        <link href="{% static 'css/base.css' %}" rel="stylesheet">
    </head>
    <body>
        <div>
            <header>
                <!-- start new HTML... -->
                <div class="nav-left">
                    <h1><a href="{% url 'home' %}">Django blog</a></h1>
                </div>
                <div class="nav-right">
                    <a href="{% url 'post_new' %}">+ New Blog Post</a>
                </div>
                <!-- end new HTML... -->
            </header>

            {% if user.is_authenticated %}
                <p>Hi {{ user.username }}!</p>
                <p><a href="{% url 'logout' %}">Log out</a></p>
            {% else %}
                <p>You are not logged in.</p>
                <a href="{% url 'login' %}">Log In</a>
            {% endif %}

            {% block content %}
            {% endblock content %}
        </div>
    </body>
</html>

2. 注册

现在我们需要给用户提供注册功能

推荐的做法是用一个专门的 APP 来干这件事

2.1 创建 APP

  • 自动创建文件
bash 复制代码
python manage.py startapp accounts
  • 注册到 settings.py
    • 在 INSTALLED_APPS 列表添加如下字符串:
python 复制代码
"accounts",

2.2 URL 配置

  • learn_django/urls.py
    • urlpatterns 列表中新增如下内容
python 复制代码
path("accounts/", include("accounts.urls")),

这意味着我们需要在 accounts/ 文件夹下新建 url.py 并配置路径

  • accounts/urls.py
python 复制代码
# accounts/urls.py
from django.urls import path
from .views import SignUpView

urlpatterns = [
    path("signup/", SignUpView.as_view(), name="signup"),
]

现在,现在这个 SignUpView 视图还没创建,我们下一步在 view.py 中创建这个类。

2.3 视图

  • accounts/views.py
python 复制代码
# accounts/views.py
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views.generic import CreateView

class SignUpView(CreateView):
    form_class = UserCreationForm
    template_name = "registration/signup.html"
    success_url = reverse_lazy("login")

还记得 success_url 和 reverse_lazy 是干什么的吗?

现在就差 templates/registration/signup.html 了。

2.4 模版

  • templates/registration/signup.html
html 复制代码
<!-- templates/registration/signup.html -->
{% extends "base.html" %}

{% block content %}
<h2>Sign Up</h2>
<form method="post">{% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Sign Up</button>
</form>
{% endblock content %}

还是一如既往的简洁。这一切都归功于 CBV 机制。

有兴趣可以去了解上代码中的这两个类:

  • CreateView
  • UserCreationForm

看看它们做了什么

2.5 效果

3. bug fix

3.1 个人使用 & 分析

我开始浏览我的项目,这让我发现了一些不合逻辑的地方。

其原因如下:

  • 因为我新增了用户注册、登录、登出 的功能
  • 这个功能与之前的页面:新建、编辑、删除 有逻辑上的联系
  • 这个联系就在于 用户 & 作者 两者的联系
    • 当前用户是作者这个集合中的一个元素
    • 用户的操作权限应该仅限于该用户所创建的博客
    • 未登录的时候只能赋予"浏览"权限

最终我总结了一下,我的页面应该具备以下逻辑:

  • 在我没登录的时候,不应该提供:
    • "新建、编辑、删除" 功能
  • 在我登录之后
    • "新建页面"不需要提供 author 选项,直接采用登录的用户即可
    • 我只能编辑、删除当前用户创建过的页面

3.2 代码修改

  • blog/views.py
    • 在"创建博客"的视图中,去掉 author 的选项,直接设置为当前用户
python 复制代码
class BlogCreateView(CreateView):
    model = Post
    template_name = "post_new.html"
    fields = ["title", "body"]
    
    def form_valid(self, form):
        form.instance.author = self.request.user  # 设置当前用户为作者
        return super().form_valid(form)
  • templates/base.html
    • 用 {% if user.is_authenticated %} 包裹了"新建博客"的链接
html 复制代码
                {% if user.is_authenticated %}
                <div class="nav-right">
                    <a href="{% url 'post_new' %}">+ New Blog Post</a>
                </div>
                {% endif %}
  • templates/post_detail.html
    • 使用 {% if user.is_authenticated and user == post.author %} 包裹了"编辑、删除"功能
python 复制代码
<!-- 只有作者才能看到编辑和删除链接 -->
{% if user.is_authenticated and user == post.author %}
    <a href="{% url 'post_edit' post.pk %}">+ Edit Blog Post</a>
    <p><a href="{% url 'post_delete' post.pk %}">+ Delete Blog Post</a></p>
{% endif %}
相关推荐
Mr数据杨2 小时前
【Dv3Admin】Django动态配置首页仪表盘
python·django·sqlite
IMPYLH2 小时前
Lua 的 UTF-8 模块
开发语言·笔记·后端·游戏引擎·lua
qq_12498707532 小时前
基于springboot的个性化服装搭配推荐小程序(源码+论文+部署+安装)
spring boot·后端·spring·微信小程序·小程序·毕业设计·毕业设计源码
cnnews2 小时前
在AWS Lambda上部署 tokenizers
python·云计算·numpy·aws·lambda·onnxruntime·tokenizers
清水白石0082 小时前
Python 虚拟环境完全指南:venv、virtualenv、conda、pipenv 深度对比与实战选择
python·conda·virtualenv
uzong2 小时前
我们常常谈复盘,那么什么是真正的复盘
后端
Cobyte2 小时前
面试官:大模型是怎么调用工具的呢 ?
前端·后端·aigc
铁手飞鹰2 小时前
[精通Python设计模式]笔记
笔记·设计模式
宵时待雨2 小时前
C++笔记归纳8:stack & queue
开发语言·数据结构·c++·笔记·算法