提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、管理员
1.表结构
首先在models.py文件下定义Admin这个类,同时用djando命令生成数据库表(python manage.py makemigrations;python manage.py migrate)数据库下才有app01_admin这个数据表。
python
#models.py
class Admin(models.Model):
"""管理员"""
username = models.CharField(verbose_name="用户名",max_length=32)
password = models.CharField(verbose_name="密码",max_length=64)
def __str__(self):
return self.username #连接表中所显示的内容
2.layout.html文件下添加管理员账号的导航
python
<li><a href="/admin/list/">管理员账户</a></li>
3.urls.py文件(POST请求传递nid)
python
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
4.form.py文件(密码加密,确认密码,重置密码与原密码要求不一致)
python
from django import forms
from django.core.exceptions import ValidationError
from app01 import models
from app01.utils.encrypt import md5
from app01.utils.bootstrap import BootstrapModelForm
class AdminModelForm(BootstrapModelForm):
confirm_password = forms.CharField(
label="确认密码",
widget=forms.PasswordInput(render_value=True))
class Meta:
model = models.Admin
fields = ["username", 'password', 'confirm_password']
widgets = {
"password": forms.PasswordInput(render_value=True)
#render_value=True密码错误也不会置空
}
def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)
def clean_confirm_password(self):
pwd = self.cleaned_data.get("password")
confirm = md5(self.cleaned_data.get("confirm_password"))
if confirm != pwd:
raise ValidationError("密码不一致")
# 返回的数值保存在数据库中
return confirm
class AdminEditModelForm(BootstrapModelForm):
class Meta:
model = models.Admin
fields = ['username'] # 只允许编辑用户名,其他信息不能编辑
class AdminResetModelForm(BootstrapModelForm):
confirm_password = forms.CharField(
label="确认密码",
widget=forms.PasswordInput(render_value=True))
class Meta:
model = models.Admin
fields = ["password", "confirm_password"]
widgets = {
"password": forms.PasswordInput(render_value=True)
}
def clean_password(self):
pwd = self.cleaned_data.get("password")
md5_pwd = md5(pwd)
# 去数据库校验当前密码和输入密码是否一致
exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
if exists:
raise ValidationError("与之前密码一致")
return md5_pwd
def clean_confirm_password(self):
pwd = self.cleaned_data.get("password")
confirm = md5(self.cleaned_data.get("confirm_password"))
if confirm != pwd:
raise ValidationError("密码不一致")
# 返回的数值保存在数据库中
return confirm
5.admin.py文件
(用户是否存在/登录、搜索、分页、编辑前确认所编辑对象存在于数据库中、编辑时显示编辑前字段的信息、添加页面相同时写入模板文件传递标题)
python
from django.shortcuts import render, redirect
from app01 import models
from app01.utils.pagination import Pagination
from app01.utils.form import AdminModelForm,AdminEditModelForm,AdminResetModelForm
def admin_list(request):
"""管理员列表"""
"""检查用户是否登录,已登录继续走下去,未登录,跳转到登录页面
用户发来请求,获取cookie随机字符串,拿着随机字符串看session中有没有"""
#是否登录
info = request.session["info"]
if not info:
return redirect("/login/")
# 搜索
data_dict = {}
search_data = request.GET.get('q', "")
if search_data:
data_dict["username__contains"] = search_data
# 根据搜索条件去数据库获取
queryset = models.Admin.objects.filter(**data_dict)
# 分页
page_object = Pagination(request, queryset, page_size=3)
context = {
'queryset': page_object.page_queryset,
'page_string': page_object.html(),
'search_data': search_data,
}
return render(request, "admin_list.html", context)
def admin_add(request):
"""添加管理员"""
title = "新建管理员"
if request.method == "GET":
form = AdminModelForm()
#change.html为添加模板
return render(request, 'change.html', {"form": form, "title": title})
form = AdminModelForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('/admin/list')
return render(request, 'change.html', {"form": form, "title": title})
def admin_edit(request, nid):
"""编辑管理员"""
row_object = models.Admin.objects.filter(id=nid).first()
if not row_object:
return render(request, "error.html", {"msg": "数据不存在"})
title = "编辑管理员"
if request.method == "GET":
form = AdminEditModelForm(instance=row_object) # 输入框内显示的默认值
return render(request, 'change.html', {"form": form, "title": title})
form = AdminEditModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect("/admin/list")
return render(request, 'change.html', {"form": form, "title": title})
def admin_delete(request, nid):
models.Admin.objects.filter(id=nid).delete()
return redirect('/admin/list/')
def admin_reset(request, nid):
"""重置密码"""
row_object = models.Admin.objects.filter(id=nid).first()
if not row_object:
return redirect('/admin/list/')
title = "重置密码-{}".format(row_object.username)
if request.method == "GET":
form = AdminResetModelForm()
return render(request, 'change.html', {"form": form, "title": title})
form = AdminResetModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect("/admin/list/")
return render(request, 'change.html', {"form": form, "title": title})
二、中间件(实现登录校验)
#info用于验证用户是否登录过,以便能否访问其他页面
在其他需要登录才能访问的页面中,都要加入:
python
#是否登录
info = request.session["info"]
if not info:
return redirect("/login/")
1.中间件的作用
可以在请求到达视图函数之前执行操作。这使得你可以在请求处理之前进行身份验证 、权限检查、日志记录等操作。
在appo01目录下创建middleware目录,并创建auth.py文件
2.定义中间件
python
#auth.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
class AuthMiddleware(MiddlewareMixin):
"""中间件"""
def process_request(selfself,request):
#0.排除那些不需要登录就能访问的页面
#request.path_info 获取当前用户请求的url /login/
if request.path_info in["/login/","/image/code/"]:
return
#1.读取当前访问的用户的session信息,如果能读到,说明已经登录过,可以继续向后走
info_dict = request.session.get("info")
print(info_dict)
if info_dict:
return
#2.没有登录过,重新回到登录页面
return redirect("/login/")
3.应用中间件
并在settings.py文件下的MIDDLEWARE中添加中间件auth.py的路径
4.在中间件的process_request方法
#如果方法中没有返回值(返回None),继续向后走
#如果有返回值HttpResponse\render\redirect,则不再继续向后执行
三、图片验证码及登录界面
1.图片验证码
python
pip install pillow
python
def image_code(request):
"""生成图片验证码"""
# 调用pillow函数,生成图片
img, code_string = check_code()
print(code_string)
# 写入到自己的session中,以便后续获取验证码再进行校验
request.session['imge_code'] = code_string
# 给session设置60*60*24*7秒超时
request.session.set_expiry(60 * 60 * 24 * 7)
#内存文件BytesIO
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
2.登录界面
POST提交需要添加: {% csrf_token %}
消除浏览器自带提示:在form内添加 novalidate
html
#html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style>
.account {
width: 450px;
border: 1px solid gray;
height: 400px;
margin-left: auto;
margin-right: auto;
margin-top: 150px;
padding: 40px 20px 40px 20px;
border-radius: 5px;
box-shadow: 5px 5px 5px #aaa;
}
.account h1 {
text-align: center;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="account">
<h1>用户登录</h1>
{# <form method="post" action = "{% url 'admin' %}">#}
<form method="post" novalidate>
{% csrf_token %}
<div >
<label>用户名</label>
{{ form.username }}
<span style="color: red;">{{ form.username.errors.0 }}</span>
</div>
<div class="form-group">
<label>密码</label>
{{ form.password }}
<span style="color: red;">{{ form.password.errors.0 }}</span>
</div>
<div class="form-group"><!---->
<div>
<label>图片验证码</label>
</div>
<div class="col-lg-7">
{{ form.code }}
<span style="color: red;">{{ form.code.errors.0 }}</span>
</div>
<img data-v-66879da5="" alt="验证码"
src="/image/code/"
class="img-logo" style="margin-left: 20px">
</div>
<div>
<button type="submit" class="btn btn-primary" style="margin-top: 18px;">登 录</button>
</div>
</form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
python
class LoginForm(BootstrapForm):
#Form组件需要手动写字段
username = forms.CharField(
label="用户名",
widget=forms.TextInput(),
# widget=forms.TextInput(attrs={"class":"form-group"}),
required=True # 必填,不能为空
)
password = forms.CharField(
label="密码",
widget=forms.PasswordInput(render_value=True),
required=True # 必填,不能为空
)
code = forms.CharField(
label="验证码",
widget=forms.TextInput,
required=True # 必填,不能为空
)
class Meta:
model = models.Admin
fields = ['username', 'password']
def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)
def login(request):
"""登录"""
if request.method == "GET":
form = LoginForm()
return render(request, 'login.html', {"form": form})
form = LoginForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)#验证成功,获取用户名和密码
user_input_code = form.cleaned_data.pop('code')
code = request.session.get('imge_code')
if code.upper() != user_input_code.upper():
form.add_error("code", "验证码错误") # 主动在password下添加错误提示
return render(request, 'login.html', {"form": form})
# 去数据库校验用户名和密码是否正确,获取用户对象
admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
if not admin_object:
form.add_error("password", "用户名或密码错误") # 主动在password下添加错误提示
return render(request, 'login.html', {"form": form})
# 用户名和密码正确
# 网站生成随机字符串,写到用户浏览器的cookie中,在写入到session中
request.session["info"] = {"id": admin_object.id, "name": admin_object.username}
#info用于验证用户是否登录过,以便能否访问其他页面
return redirect("/admin/list/")
return render(request, 'login.html', {"form": form})
四、注销用户(退出登录)
python
def logout(request):
"""注销"""
request.session.clear()
return redirect('/login/')
python
登录完成,则{{ request.session.info.name }}一定存在,可以直接传到html中