一、分析
在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语句在这里结束 -->
八、查看效果