前言
之前我们的"博客页面"项目已经有了如下功能:
- 查看所有博客、博客具体页面
- 新增博客
- 编辑博客
- 删除博客
这意味着我们的核心操作已经完成。但是还没有给用户提供账号相关功能
- 注册
- 登入
- 登出
用户账户的这些功能如果自己实现显然会有很多可预见的问题,比如各种字符串校验、重名检查、安全校验 等等。
好在 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
- 在 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 是干什么的吗?
- success_url 页面成功后我应该跳转到哪里
- reverse_lazy 延迟获取名为 login 的页面 url
- 还记得为什么要延迟吗?可以看看
现在就差 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 %}