一、分析

在Django中用app来区分不同功能的模块,达到代码隔离和复用。因为用户管理和博客文章的功能不能,因此需要新建一个专门的app。

进入虚拟环境,运行startapp指令创建新的​app​

python manage.py startapp userprofile

app创建完之后还需要app配置:

1、打开my_blog/urls.py,加入userprofile用户模块的路由分发

urlpatterns = [
path('admin/', admin.site.urls),

# 新增代码,配置app的url
path('article/', include('article.urls', namespace='article')),

# 用户管理
path('userprofile/', include('userprofile.urls', namespace='userprofile')),

]

2、打开my_blog/settings.py,注册app

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 新增'article'代码,激活app
'article',
'userprofile',
]

二、创建表单

用户登录时,需要填写账户密码等表单数据,因此又要用到Form表单类。

userprofile目录中创建表单类的文件​forms.py​,编写如下代码

# 引入表单类
from django import forms
# 引入User模型
from django.contrib.auth.models import User

# 登录表单,继承了forms.Form类
class UserLoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField()

在前面发表文章的模块中,表单类继承了​​forms.ModelForm​​​,这个父类适合于需要直接与数据库交互的功能,比如新建、更新数据库的字段等。如果表单将用户直接添加或编辑Django模型,则可以使用​​ModelForm​​来避免重复书写字段描述。

而​​forms.Form​​​则需要手动配置每个字段,它适用于不与数据库进行直接交互的功能。用户登录不需要对数据库进行任何改动,因此直接继承​​forms.Form​​就可以了。


三、编写视图

用户的登录是比较复杂的功能,好在Django提供了封装好的模块供我们使用。

userprofile/views.py中写视图函数

from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from .forms import UserLoginForm

def user_login(request):
if request.method == 'POST':
user_login_form = UserLoginForm(data=request.POST)
if user_login_form.is_valid():
# .cleaned_data 清洗出合法数据
data = user_login_form.cleaned_data
# 检验账号、密码是否正确匹配数据库中的某个用户
# 如果均匹配则返回这个user对象
user = authenticate(username=data['username'],password=data['password'])
if user:
# 将用户数据存在session中,即实现了登录动作
login(request,user)
return redirect("article:article_list")
else:
return HttpResponse("账号或密码输入有误,请重新输入~")

else:
return HttpResponse("账号或密码不合法")
elif request.method == 'GET':
user_login_form = UserLoginForm()
context = {'form': user_login_form}
return render(request, 'userprofile/login.html',context)

else:
return HttpResponse("请使用GET或POST请求数据")
  • 跟发表文章的表单类类似,Form对象的主要任务就是验证数据。调用​​is_valid()​​方法验证并返回指定数据是否有效的布尔值;
  • ​Form​​​不仅负责验证数据,还可以“清洗”它:将其标准化为一致的格式,这个特性使得它允许以各种方式输入特定字段的数据,并且始终产生一致的输出。一但​​Form​​​使用数据创建了一个实例并对其进行了验证,就可以通过​​cleaned_data​​属性访问清洗之后的数据;
  • ​authenticate()​​方法验证用户名称和密码是否匹配,如果是,则将这个用户数据返回;
  • ​login()​​方法实现用户登录,将用户数据保存在session中;

Session在网络应用中,称为“会话控制”,它存储特定用户会话所需的属性即配置信息。
当用户在Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去;
Session最常见的用法就是存储用户的登录数据;


四、编写登录模板

创建templates/userprofile/login.html模板

{% extends "base.html" %} {% load staticfiles %}
{% block title %} 登录 {% endblock title %}

{% block content %}
<div class="container">
<div class="row">
<div class="col-12">
<br>
<form method="post" action=".">
{% csrf_token %}
<!-- 账号 -->
<div class="form-group">
<label for="username">账号</label>
<input type="text" class="form-control" id="username" name="username">
</div>
<!-- 密码 -->
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" name="password">
</div>
<!-- 提交按钮 -->
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
</div>
  • ​type="password"​​可以让输入密码的时候显示小圆点,避免有人偷窥;

五、增加登录入口

改写templates/header.html,把登录的按钮加进行

<!-- 导航入口 -->
<div>
<ul class="navbar-nav">
<!-- 条目 -->
<li class="nav-item">
<a class="nav-link" href="{% url 'article:article_create' %}">写文章</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'article:article_list' %}">文章</a>
</li>

<!-- Django的if模板语句 -->
{% if user.is_authenticated %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ user.username }}</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{% url 'userprofile:logout' %}">退出登录</a>
</div>
</li>
<!-- 如果用户未登录,则显示登录 -->
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'userprofile:login' %}">登录</a>
</li>
<!-- if语句在这里结束 -->
{% endif %}

</ul>
</div>

这里使用的新的模板语法:{% if … %},来判断用户是否已经登录:

  • 如果用户已经登录,则显示一个名字为用户名称的下拉框,就行通常的社交网站一样;
  • 如果用户未登录,则显示“登录”两个字提醒用户可以点击登录;

​is_authenticated​​​是​​models.User​​类的属性,用于判断用户是否已通过身份验证。


六、路由配置

创建userprofile/urls.py文件,并写入如下代码

from django.urls import path
from . import views

app_name = 'userprofile'

urlpatterns = [
# 用户登录
path('login/', views.user_login, name='login'),

]

七、用户的退出

1、打开userprofile/views.py添加用户退出的视图

...
from django.contrib.auth import authenticate, login, logout

...

# 用户退出
def user_logout(request):
logout(request)
return redirect("article:article_list")

2、打开userprofile/urls.py进行路由配置

urlpatterns = [
# 用户登录
path('login/', views.user_login, name='login'),
# 用户退出
path('logout/', views.user_logout, name="logout"),
]

3、退出登录入口
在写登录的代码时,已经给用户退出留好了接口,因此只需要改动​​​templates/header.html​

...
<!-- 如果用户未登录,则显示登录 -->
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'userprofile:login' %}">登录</a>
</li>
<!-- if语句在这里结束 -->

八、查看效果

Django搭建个人博客--用户的登录和登出_数据


Django搭建个人博客--用户的登录和登出_表单_02


Django搭建个人博客--用户的登录和登出_表单_03