来源引用网络知识与某站曹老师视频相互结合学习记录,仅供参考!
Django 内置 Auth 认证系统
在开发一个网站的时候,无可避免的需要设计实现网站的用户系统;但是此时用户界面,例如访客、会员页面也需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,需要集成到一套系统里面去,所以需要Django 内置的 Auth 认证系统;Django作为一个完美主义者的终极框架,它内置了强大的用户认证系统,它默认使用 auth_user 表来存储用户数据;之前已经通过数据迁移生成了用户权限认证系统的物理表,里面包含系统用户表,权限表,用户组,以及用户组权限关联表,用户和组关联表,用户权限关联表。
实现 Auth 认证系统里的用户注册的话,使用的是 auth 模版 models.py 里定义的 User 模型,通过 auth内置的 User 类,可以直接操作用户相关功能;

用户注册功能实现
模拟用户注册
1、在"djangoProject"项目"templates"目录文件路径下新建名称为"auth"的目录文件,在"auth"目录文件路径下再新建名称为"register(注册页面)"和"login(登录页面)"的 HTML 文件,分别输入以下内容;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="/auth/register" method="post">
{% csrf_token %}
<table>
<tr>
<th>用户注册</th>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" value="{{ username }}"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" value="{{ password }}"></td>
</tr>
<tr>
<td>
<input type="submit" value="提交">
</td>
<td>
<font color="red">{{ errorInfo }}</font>
</td>
</tr>
</table>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title登录页面</title>
</head>
<body>
临时登录页面
</body>
</html>

2、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容,定义 to_register 和 register 两个方法,新增用户用的是 create_user,判断用户是否存在通过 filter 检验用户名是否存在;
# 导包
import datetime
import os
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db import connection, transaction
from django.db.backends.utils import CursorDebugWrapper
from django.db.models import Q, Sum, Avg, F
from django.http import HttpResponse, HttpResponseNotFound, JsonResponse, StreamingHttpResponse, FileResponse
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from helloWorld.forms import StudentForm, BookInfoForm, BookInfoModelForm
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo, AccountInfo
# Create your views here.
# 定义类
class Person:
# 属性 姓名
name = None
# 属性 年龄
age = None
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义一个index方法,里面要加上request请求对象
def index(request):
# 传递字符串类型数据,定义字符串类型变量str
str = 'hello world!'
# 日期对象date,导包引入import datetime
date = datetime.datetime.now()
# 定义字典类型数据
myDict = {"Jack":"11", "Queen":"12", "King":"13"}
# 创建一个对象,例如:zhangsan
zhangsan = Person("张三", 18)
# 定义列表myList、元组myTuple--列表和元组里面的元素类型没有限制,列表里面可以嵌套列表,元组里面可以嵌套元组
myList = [1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10}]
myTuple = (1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10})
# 变量content_value是字典格式
content_value = {"content_msg": str, "msg2": myDict, "msg3": zhangsan, "msg4": myList, "msg5": myTuple, "date": date}
# context= 传递的本身要求格式是一个字典类型
return render(request, 'index.html', context=content_value)
# 定义index_id方法,里面第一个参数request请求对象,第二个参数 id
def index_id(request, id):
# 判断 id是否为0
if id == 0:
# 导包引入redirect模块,如果id等于0的话,重定向到一个目标静态地址
return redirect("/static/error.html")
else:
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse("id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,里面继续跟多个路由变量"year, month, day, id"
def index_id02(request, year, month, day, id):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + "/" + str(month) + "/" + str(day) + "/" +"id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,后面跟多个路由变量"year, month, day"--注意,使用正则后不能与"id"再混合使用了
def index_id03(request, year, month, day):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + '/' + str(month) + '/' + str(day) + "使用正则路由后的某某平台系统页面")
# 定义目标文件路径
file_path = "D:\\works\\djangoProject\\datas\\IDM.rar"
# 定义download_file1下载方法,请求需要带上request(所有的请求都要带上request)
def download_file1(request):
# 定义文件--使用open函数方法以"rb"二进制读取模式打开文件--然后返回一个file文件对象
file = open(file_path, 'rb')
# 创建构造好了HttpResponse对象之后返回给response
response = HttpResponse(file)
# 指定文件类型
response['Content-Type'] = 'application/rar-compressed'
# 扩展--指定附件及文件名字(可以动态拼接filename,并不建议使用原始名称)
response['Content-Disposition'] = 'attachment; filename=file1.rar'
return response
def download_file2(request):
file = open(file_path, 'rb')
# 创建构造好了StreamingHttpResponse对象之后返回给response
response = StreamingHttpResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file2.rar'
return response
def download_file3(request):
file = open(file_path, 'rb')
# 创建构造好了FileResponse对象之后返回给response
response = FileResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file3.rar'
return response
def get_test(request):
"""
get 请求测试
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'打印常用属性request.content_type:{request.content_type}')
print(f'打印常用属性request.content_params:{request.content_params}')
print(f'打印常用属性request.COOKIES:{request.COOKIES}')
print(f'打印常用属性request.scheme:{request.scheme}')
print(f'打印常用方法request.is_secure:{request.is_secure()}')
print(f'打印常用方法request.get_host:{request.get_host()}')
print(f'打印常用方法request.get_full_path:{request.get_full_path()}')
print(f'使用request.GET.get("name")方法获取对应key值参数:{request.GET.get("name")}' )
print(f'使用request.GET.get("pwd")方法获取对应key值参数:{request.GET.get("pwd")}')
print(f'使用request.GET.get("dev")方法获取不存在的参数,返回值是'None':{request.GET.get("dev")}')
print(f'request.GET.get("prod", "555")获取的prod参数是不存在的,设置返回值'555':{request.GET.get("prod", "555")}')
return HttpResponse("hello world!http get ok!")
def post_test(request):
"""
post 请求测试方法
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'使用request.POST.get("name")方法获取对应key值参数:{request.POST.get("name")}')
print(f'使用request.POST.get("pwd")方法获取对应key值参数:{request.POST.get("pwd")}')
print(f'使用request.POST.get("dev")方法获取不存在的参数,返回值是'None':{request.POST.get("dev")}')
print(f'request.POST.get("prod", "556")获取的prod参数是不存在的,设置返回值'556':{request.POST.get("prod", "556")}')
return HttpResponse("hello world!http post ok!")
def to_login(request):
"""
跳转到登录页面
:param request:
:return:
"""
# 跳转到登录页面可直接使用渲染render()方法
return render(request, 'login.html')
def login(request):
"""
登录到主页面
:param request:
:return:
"""
# 首先获取用户名和密码
user_name = request.POST.get('user_name')
pwd = request.POST.get('pwd')
# 模拟用户登录(暂不连接数据库)
if user_name == "python3" and pwd == "123456":
# session中存一个用户名
request.session['currentUserName'] = user_name
print(f'代码脚本中session获取:{request.session['currentUserName']}')
# 获取HttpResponse
response = render(request, 'main.html')
# 通过response.set_Cookie()方法来设置cookie
response.set_cookie('remember_me', True)
return response
else:
# 定义变量content_value为报错提示信息,里面是键值对格式的对象
content_value = {"error_info":"用户名或者密码错误!"}
return render(request, 'login.html', context=content_value)
def to_upload(request):
"""
跳转到上传文件页面
:param request:
:return:
"""
return render(request, 'upload.html')
def upload(request):
"""
上传文件处理
:param request:
:return:
"""
# 获取上传的文件,如果没有文件,就默认为None(如果不写指定的None,也是默认None)
myFile = request.FILES.get("myfile", None)
# 判断如果是有myFile的情况,就是说明有文件
if myFile:
# 打开特定的文件进行二进制的写操作--上传文件路径烦请自行创建(例如:在项目datas路径下新建"myFile"目录文件)
f = open(os.path.join("D:\\works\\djangoProject\\datas\\myFile", myFile.name), "wb+")
# 分块写入文件
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("文件上传成功!")
else:
return HttpResponse("没有发现可以上传的文件!")
# 定义List类,继续继承ListView(导包引入 from django.views.generic import ListView)
class List(ListView):
# 设置模版文件
template_name = 'student/list.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息列表'}
# 定义数据集(查询结果集)--StudentInfo(导入 from helloWorld.models import StudentInfo)
queryset = StudentInfo.objects.all()
# 每页展示数据的条数(自行设置)
paginate_by = 5
# 设置上下文对象名称(其实就是一个列表的对象),建议使用自定义名称,不然就默认为 objectlist
context_object_name = 'student_list'
# 定义Detail类,继续继承DetailView(导包引入 from django.views.generic import DetailView)
class Detail(DetailView):
# 设置模版文件
template_name = 'student/detail.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息详情'}
# 设置查询模型--指定model(不然无法查询数据)
model = StudentInfo
# 设置上下文对象名称
context_object_name = 'student'
# 指定URL中用于获取对象的唯一标识符的参数名称,默认为'pk';
# 如若在urls.py文件中自定义了名称,则需要添加对应pk_url_kwarg参数为自定义名称
# pk_url_kwarg = 'id'
# 定义Create类,继续继承CreateView(导包引入 from django.views.generic import CreateView)
class Create(CreateView):
# 设置模版文件,名称修改为create(有的名称叫"add"也行)
template_name = 'student/create.html'
# 设置模型外的数据--例如:指定标题"添加"或者"新增"都行
extra_context = {'title': '学生信息新增'}
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Update类,继续继承UpdateView(导包引入 from django.views.generic import UpdateView)
class Update(UpdateView):
# 设置模版文件,名称修改为update(自定义)
template_name = 'student/update.html'
# 设置模型外的数据--例如:指定标题"编辑"或者"修改"都行
extra_context = {'title': '学生信息编辑'}
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Delete类,继续继承DeleteView(导包引入 from django.views.generic import DeleteView)
class Delete(DeleteView):
# 设置模版文件,名称修改为delete(自定义)
template_name = 'student/delete.html'
# 设置模型外的数据--例如:指定标题"删除"或者"修改"都行
extra_context = {'title': '学生信息删除'}
# 设置上下文对象名称
context_object_name = 'student'
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 自定义跳转子类模板页面方法
def to_course(request):
"""
跳转到子类模板页面
:param request:
:return:
"""
return render(request, 'course.html')
# 定义bookList方法
def bookList(request):
"""
图书列表查询
"""
# 查询显示所有数据
bookList = BookInfo.objects.all()
# 使用BookInfo.objects.extra()方法,里面使用where加参数(元组格式),在params加上具体的参数,也是一个元组
# 如果是模型外的参数(models.py里面没有定义的参数),可以使用BookInfo.objects.select()方法
# bookList = BookInfo.objects.extra(where=["price>%s"], params=[90])
# # 使用BookInfo.objects.raw()方法,直接写一个SQL语句
# bookList = BookInfo.objects.raw('SELECT * FROM t_book where price>%s', params=[90])
# 使用connection方法需要导包引入from django.db import connection模块,返回一个cursor游标
# 指定cursor游标为CursorDebugWrapper类型,需导包引入from django.db.backends.utils import CursorDebugWrapper模块
cursor: CursorDebugWrapper = connection.cursor()
# 然后就可以执行使用execute方法,查询图书价格大于90的记录数
# cursor.execute('select count(*) from t_book where price>90')
# print('预计提取的一个结果是(2,):', cursor.fetchone())
content_value = {"title": "图书列表", "bookList": bookList}
return render(request, 'book/list.html', context=content_value)
def bookList2(request):
"""
多表查询,有正向查询和反向查询
:param request:
:return:
"""
# 正向查询(经常使用)--多的一端BookInfo条件id=2且只查询一条数据,返回图书book并指定类型BookInfo
book: BookInfo = BookInfo.objects.filter(id=2).first()
# 能够输出book的所有信息,也能输出所关联的bookType.bookTypeName数据信息
print(book.bookName, book.bookType.bookTypeName)
# 反向查询(很少使用)--(导包引入from helloWorld.models import BookTypeInfo)
# 一的一端BookTypeInfo条件id=1且只查询一条数据,返回图书类别bookType并指定类型BookTypeInfo
bookType: BookTypeInfo = BookTypeInfo.objects.filter(id=1).first()
# 输出读取关联的这个图书类别下的所有图书的数据集中第一条数据,固定语法bookinfo_set
print(bookType.bookinfo_set.first().bookName)
# 显示这个类别下的所有数据,返回的结果是一个QuerySet数据集,这个类型下有两条数据,
print(bookType.bookinfo_set.all())
# 把QuerySet这个数据集转发到页面上就可以进行遍历了
content_value = {"title": "图书列表", "bookList": bookType.bookinfo_set.all()}
return render(request, 'book/list.html', context=content_value)
def preAdd(request):
"""
预处理,添加操作
:param request:
:return:
"""
# 预处理操作需要先找到所有数据
bookTypeList = BookTypeInfo.objects.all()
print(f'可自行打印查看bookTypeList是否查询出所有数据:{bookTypeList}')
# 预处理操作之后要返回到图书添加页面
content_value = {"title": "图书添加", "bookTypeList": bookTypeList}
return render(request, 'book/add.html', context=content_value)
def preAdd2(request):
"""
预处理,添加操作 使用form表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoForm
form = BookInfoForm()
context_value = {"title": "图书添加2", "form": form}
return render(request, 'book/add2.html', context_value)
def preAdd3(request):
"""
预处理,添加操作 使用ModelForm表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoModelForm
form = BookInfoModelForm()
context_value = {"title": "图书添加3", "form": form}
return render(request, 'book/add3.html', context_value)
def add(request):
"""
图书添加
:param request:
:return:
"""
# 封装对象
book = BookInfo()
# 添加数据
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType")
book.price = request.POST.get("price")
# 因为是模板,所以直接使用save()方法
book.save()
# 数据添加完成之后,可以获取新增数据的主键id
print(f'数据添加完成之后,获取新增数据的主键id:{book.id}')
# 添加完成之后,需要返回到列表,直接return返回那个对象
return bookList(request)
# 修改预处理,定义修改操作方法;页面需要传一个id来确定是要修改哪一条记录
def preUpdate(request, id):
"""
预处理,修改操作
:param request:
:return:
"""
print("通过path里面的变量,页面需要传一个id来确定是要修改哪一条记录:", id)
# 根据传过来的id去查询数据,并返回一个book对象
book = BookInfo.objects.get(id=id)
print(f'可自行打印查看返回的book对象:{book}')
bookTypeList = BookTypeInfo.objects.all()
print(bookTypeList)
# book对象也需要传到页面上去,到时候页面上就能够取值了
content_value = {"title": "图书修改", "bookTypeList": bookTypeList, "book": book}
return render(request, 'book/edit.html', context=content_value)
def update(request):
"""
图书修改
:param request:
:return:
"""
book = BookInfo()
book.id = request.POST.get("id")
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType_id")
book.price = request.POST.get("price")
book.save()
return bookList(request)
def delete(request, id):
"""
图书删除
:param request:
:return:
"""
# 删除指定id数据
BookInfo.objects.get(id=id).delete()
# 根据条件删除多条数据
# BookInfo.objects.filter(price__gte=100).delete()
# 删除所有数据
# BookInfo.objects.all().delete()
return bookList(request)
# 定义转账transfer方法--导包引入from django.db import transaction模块使用事务
@transaction.atomic
def transfer(request):
"""
模拟转账
:param request:
:return:
"""
# 开启事务,
sid = transaction.savepoint()
# 添加异常处理机制
try:
# 导包引入from helloWorld.models import AccountInfo方法
# AccountInfo.objects.filter()方法查找A用户
a1 = AccountInfo.objects.filter(user='A用户_赵大')
# 导包引入from django.db.models import F 模块
a1.update(account = F('account') + 100)
# 这个"'A用户_赵大'"账户是加account余额,那么对应的"'B 用户_ 钱二'"账户就是减account余额
b2 = AccountInfo.objects.filter(user='B用户_钱二')
# 修改操作
b2.update(account = F('account') - 100 / 0)
# 提交事务,如果不设置,当程序执行完成后,会自动提交事务
transaction.savepoint_commit(sid)
except Exception as e:
print(f'异常信息为:{e}')
# 事务回滚--传一个sid表示需要事务回滚哪一个事务
transaction.savepoint_rollback(sid)
# 执行完两个操作之后,模拟转账完成,返回到界面
return HttpResponse("OK!转账完成!")
def to_register(request):
"""
跳转注册页面
:param request:
:return:
"""
return render(request, 'auth/register.html')
def register(request):
"""
用户注册
:param request:
:return:
"""
# 首先需要获取用户名密码参数
username = request.POST.get('username')
password = request.POST.get('password')
# 导包引入from django.contrib.auth.models import User模型,使用封装好的create_user方法操作数据库
User.objects.create_user(username=username, password=password)
return render(request, "auth/login.html")

3、修改"djangoProject"应用下的"urls.py"配置文件内容,配置定义映射关系;
"""
URL configuration for djangoProject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.contrib import admin
from django.urls import path, re_path, include
from django.views.generic import RedirectView
from django.views.static import serve
import helloWorld.views
urlpatterns = [
path('admin/', admin.site.urls),
# 可直接复制上面"admin",把"admin"修改为"index";后面是跟的"处理函数helloWorld.views.index"
# 是helloWorld应用的views里面的index()--引入helloWorld.views,记得index后不能加小括号,因为传入的是对象;
path('index/', helloWorld.views.index, name='index'),
# 要是请求"redirectTo"这个请求的话给重定向到"index"--重定向使用RedirectView.as_view(),里面使用关键词参数url
path('redirectTo', RedirectView.as_view(url="index/")),
# 自定义名称,例如叫"index_id/",后面再跟上某网页id;<int:id> int指定类型,路由变量为id;对应对应的路由映射
path('index_id/<int:id>', helloWorld.views.index_id),
# 多个路由变量
path('index_id02/<int:year>/<int:month>/<int:day>/<int:id>', helloWorld.views.index_id02),
# 正则表达式匹配是必须使用re_path方法,正则表达式"?P"开头是固定格式
re_path('index_id03/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})', helloWorld.views.index_id03),
# 配置媒体文件的路由地址
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 命名空间namespace--比如说是"user/"开头的,第一个参数include(),第二个参数namespace
# 导包引入include模块,include()里面也有两个参数,第一个是指定user的urls,第二个是项目名;
path('user/', include(('user.urls', 'user'), namespace='user')),
path('order/', include(('order.urls', 'order'), namespace='order')),
# 配置 download_file
path('download1/', helloWorld.views.download_file1),
path('download2/', helloWorld.views.download_file2),
path('download3/', helloWorld.views.download_file3),
path('get', helloWorld.views.get_test),
path('post', helloWorld.views.post_test),
path('toLogin/', helloWorld.views.to_login),
path('login', helloWorld.views.login),
path('toUpload/', helloWorld.views.to_upload),
path('upload', helloWorld.views.upload),
path('student/list', helloWorld.views.List.as_view()),
# 默认名称就是"pk",建议不要更改,在开发过程中就默认为pk即可
path('student/<int:pk>', helloWorld.views.Detail.as_view()),
# 如果把默认名称"pk"更改为其他(例如:id),则需要在urls.py配置文件Detail类中添加pk_url_kwarg参数
# path('student/<int:id>', helloWorld.views.Detail.as_view())
path('student/create', helloWorld.views.Create.as_view()),
path('student/update/<int:pk>', helloWorld.views.Update.as_view()),
path('student/delete/<int:pk>', helloWorld.views.Delete.as_view()),
path('toCourse/', helloWorld.views.to_course),
path('book/list', helloWorld.views.bookList),
path('book/list2', helloWorld.views.bookList2),
path('book/preAdd', helloWorld.views.preAdd),
path('book/add', helloWorld.views.add),
path('book/preUpdate/<int:id>', helloWorld.views.preUpdate),
path('book/delete/<int:id>', helloWorld.views.delete),
path('book/update', helloWorld.views.update),
path('transfer/', helloWorld.views.transfer),
path('book/preAdd2', helloWorld.views.preAdd2),
path('book/preAdd3', helloWorld.views.preAdd3),
# 跳转注册页面
path('auth/toRegister', helloWorld.views.to_register),
# 提交注册请求
path('auth/register', helloWorld.views.register)
]

4、运行项目,浏览器输入"http://127.0.0.1:8000/auth/toRegister"测试验证,输入用户名、密码(例如,用户名:dev01,密码:123),点击"提交"按钮,能够跳转登录页面成功,刷新查看数据库表,已经成功添加数据信息;

优化用户注册
检验用户名是否已经存在,如果已经存在则返回注册页面,并回显注册的用户名和密码;
5、修改"helloWorld"应用下的"views.py"配置文件内容中的 register 用户注册方法;
# 导包
import datetime
import os
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db import connection, transaction
from django.db.backends.utils import CursorDebugWrapper
from django.db.models import Q, Sum, Avg, F
from django.http import HttpResponse, HttpResponseNotFound, JsonResponse, StreamingHttpResponse, FileResponse
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from helloWorld.forms import StudentForm, BookInfoForm, BookInfoModelForm
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo, AccountInfo
# Create your views here.
# 定义类
class Person:
# 属性 姓名
name = None
# 属性 年龄
age = None
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义一个index方法,里面要加上request请求对象
def index(request):
# 传递字符串类型数据,定义字符串类型变量str
str = 'hello world!'
# 日期对象date,导包引入import datetime
date = datetime.datetime.now()
# 定义字典类型数据
myDict = {"Jack":"11", "Queen":"12", "King":"13"}
# 创建一个对象,例如:zhangsan
zhangsan = Person("张三", 18)
# 定义列表myList、元组myTuple--列表和元组里面的元素类型没有限制,列表里面可以嵌套列表,元组里面可以嵌套元组
myList = [1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10}]
myTuple = (1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10})
# 变量content_value是字典格式
content_value = {"content_msg": str, "msg2": myDict, "msg3": zhangsan, "msg4": myList, "msg5": myTuple, "date": date}
# context= 传递的本身要求格式是一个字典类型
return render(request, 'index.html', context=content_value)
# 定义index_id方法,里面第一个参数request请求对象,第二个参数 id
def index_id(request, id):
# 判断 id是否为0
if id == 0:
# 导包引入redirect模块,如果id等于0的话,重定向到一个目标静态地址
return redirect("/static/error.html")
else:
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse("id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,里面继续跟多个路由变量"year, month, day, id"
def index_id02(request, year, month, day, id):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + "/" + str(month) + "/" + str(day) + "/" +"id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,后面跟多个路由变量"year, month, day"--注意,使用正则后不能与"id"再混合使用了
def index_id03(request, year, month, day):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + '/' + str(month) + '/' + str(day) + "使用正则路由后的某某平台系统页面")
# 定义目标文件路径
file_path = "D:\\works\\djangoProject\\datas\\IDM.rar"
# 定义download_file1下载方法,请求需要带上request(所有的请求都要带上request)
def download_file1(request):
# 定义文件--使用open函数方法以"rb"二进制读取模式打开文件--然后返回一个file文件对象
file = open(file_path, 'rb')
# 创建构造好了HttpResponse对象之后返回给response
response = HttpResponse(file)
# 指定文件类型
response['Content-Type'] = 'application/rar-compressed'
# 扩展--指定附件及文件名字(可以动态拼接filename,并不建议使用原始名称)
response['Content-Disposition'] = 'attachment; filename=file1.rar'
return response
def download_file2(request):
file = open(file_path, 'rb')
# 创建构造好了StreamingHttpResponse对象之后返回给response
response = StreamingHttpResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file2.rar'
return response
def download_file3(request):
file = open(file_path, 'rb')
# 创建构造好了FileResponse对象之后返回给response
response = FileResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file3.rar'
return response
def get_test(request):
"""
get 请求测试
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'打印常用属性request.content_type:{request.content_type}')
print(f'打印常用属性request.content_params:{request.content_params}')
print(f'打印常用属性request.COOKIES:{request.COOKIES}')
print(f'打印常用属性request.scheme:{request.scheme}')
print(f'打印常用方法request.is_secure:{request.is_secure()}')
print(f'打印常用方法request.get_host:{request.get_host()}')
print(f'打印常用方法request.get_full_path:{request.get_full_path()}')
print(f'使用request.GET.get("name")方法获取对应key值参数:{request.GET.get("name")}' )
print(f'使用request.GET.get("pwd")方法获取对应key值参数:{request.GET.get("pwd")}')
print(f'使用request.GET.get("dev")方法获取不存在的参数,返回值是'None':{request.GET.get("dev")}')
print(f'request.GET.get("prod", "555")获取的prod参数是不存在的,设置返回值'555':{request.GET.get("prod", "555")}')
return HttpResponse("hello world!http get ok!")
def post_test(request):
"""
post 请求测试方法
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'使用request.POST.get("name")方法获取对应key值参数:{request.POST.get("name")}')
print(f'使用request.POST.get("pwd")方法获取对应key值参数:{request.POST.get("pwd")}')
print(f'使用request.POST.get("dev")方法获取不存在的参数,返回值是'None':{request.POST.get("dev")}')
print(f'request.POST.get("prod", "556")获取的prod参数是不存在的,设置返回值'556':{request.POST.get("prod", "556")}')
return HttpResponse("hello world!http post ok!")
def to_login(request):
"""
跳转到登录页面
:param request:
:return:
"""
# 跳转到登录页面可直接使用渲染render()方法
return render(request, 'login.html')
def login(request):
"""
登录到主页面
:param request:
:return:
"""
# 首先获取用户名和密码
user_name = request.POST.get('user_name')
pwd = request.POST.get('pwd')
# 模拟用户登录(暂不连接数据库)
if user_name == "python3" and pwd == "123456":
# session中存一个用户名
request.session['currentUserName'] = user_name
print(f'代码脚本中session获取:{request.session['currentUserName']}')
# 获取HttpResponse
response = render(request, 'main.html')
# 通过response.set_Cookie()方法来设置cookie
response.set_cookie('remember_me', True)
return response
else:
# 定义变量content_value为报错提示信息,里面是键值对格式的对象
content_value = {"error_info":"用户名或者密码错误!"}
return render(request, 'login.html', context=content_value)
def to_upload(request):
"""
跳转到上传文件页面
:param request:
:return:
"""
return render(request, 'upload.html')
def upload(request):
"""
上传文件处理
:param request:
:return:
"""
# 获取上传的文件,如果没有文件,就默认为None(如果不写指定的None,也是默认None)
myFile = request.FILES.get("myfile", None)
# 判断如果是有myFile的情况,就是说明有文件
if myFile:
# 打开特定的文件进行二进制的写操作--上传文件路径烦请自行创建(例如:在项目datas路径下新建"myFile"目录文件)
f = open(os.path.join("D:\\works\\djangoProject\\datas\\myFile", myFile.name), "wb+")
# 分块写入文件
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("文件上传成功!")
else:
return HttpResponse("没有发现可以上传的文件!")
# 定义List类,继续继承ListView(导包引入 from django.views.generic import ListView)
class List(ListView):
# 设置模版文件
template_name = 'student/list.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息列表'}
# 定义数据集(查询结果集)--StudentInfo(导入 from helloWorld.models import StudentInfo)
queryset = StudentInfo.objects.all()
# 每页展示数据的条数(自行设置)
paginate_by = 5
# 设置上下文对象名称(其实就是一个列表的对象),建议使用自定义名称,不然就默认为 objectlist
context_object_name = 'student_list'
# 定义Detail类,继续继承DetailView(导包引入 from django.views.generic import DetailView)
class Detail(DetailView):
# 设置模版文件
template_name = 'student/detail.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息详情'}
# 设置查询模型--指定model(不然无法查询数据)
model = StudentInfo
# 设置上下文对象名称
context_object_name = 'student'
# 指定URL中用于获取对象的唯一标识符的参数名称,默认为'pk';
# 如若在urls.py文件中自定义了名称,则需要添加对应pk_url_kwarg参数为自定义名称
# pk_url_kwarg = 'id'
# 定义Create类,继续继承CreateView(导包引入 from django.views.generic import CreateView)
class Create(CreateView):
# 设置模版文件,名称修改为create(有的名称叫"add"也行)
template_name = 'student/create.html'
# 设置模型外的数据--例如:指定标题"添加"或者"新增"都行
extra_context = {'title': '学生信息新增'}
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Update类,继续继承UpdateView(导包引入 from django.views.generic import UpdateView)
class Update(UpdateView):
# 设置模版文件,名称修改为update(自定义)
template_name = 'student/update.html'
# 设置模型外的数据--例如:指定标题"编辑"或者"修改"都行
extra_context = {'title': '学生信息编辑'}
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Delete类,继续继承DeleteView(导包引入 from django.views.generic import DeleteView)
class Delete(DeleteView):
# 设置模版文件,名称修改为delete(自定义)
template_name = 'student/delete.html'
# 设置模型外的数据--例如:指定标题"删除"或者"修改"都行
extra_context = {'title': '学生信息删除'}
# 设置上下文对象名称
context_object_name = 'student'
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 自定义跳转子类模板页面方法
def to_course(request):
"""
跳转到子类模板页面
:param request:
:return:
"""
return render(request, 'course.html')
# 定义bookList方法
def bookList(request):
"""
图书列表查询
"""
# 查询显示所有数据
bookList = BookInfo.objects.all()
# 使用BookInfo.objects.extra()方法,里面使用where加参数(元组格式),在params加上具体的参数,也是一个元组
# 如果是模型外的参数(models.py里面没有定义的参数),可以使用BookInfo.objects.select()方法
# bookList = BookInfo.objects.extra(where=["price>%s"], params=[90])
# # 使用BookInfo.objects.raw()方法,直接写一个SQL语句
# bookList = BookInfo.objects.raw('SELECT * FROM t_book where price>%s', params=[90])
# 使用connection方法需要导包引入from django.db import connection模块,返回一个cursor游标
# 指定cursor游标为CursorDebugWrapper类型,需导包引入from django.db.backends.utils import CursorDebugWrapper模块
cursor: CursorDebugWrapper = connection.cursor()
# 然后就可以执行使用execute方法,查询图书价格大于90的记录数
# cursor.execute('select count(*) from t_book where price>90')
# print('预计提取的一个结果是(2,):', cursor.fetchone())
content_value = {"title": "图书列表", "bookList": bookList}
return render(request, 'book/list.html', context=content_value)
def bookList2(request):
"""
多表查询,有正向查询和反向查询
:param request:
:return:
"""
# 正向查询(经常使用)--多的一端BookInfo条件id=2且只查询一条数据,返回图书book并指定类型BookInfo
book: BookInfo = BookInfo.objects.filter(id=2).first()
# 能够输出book的所有信息,也能输出所关联的bookType.bookTypeName数据信息
print(book.bookName, book.bookType.bookTypeName)
# 反向查询(很少使用)--(导包引入from helloWorld.models import BookTypeInfo)
# 一的一端BookTypeInfo条件id=1且只查询一条数据,返回图书类别bookType并指定类型BookTypeInfo
bookType: BookTypeInfo = BookTypeInfo.objects.filter(id=1).first()
# 输出读取关联的这个图书类别下的所有图书的数据集中第一条数据,固定语法bookinfo_set
print(bookType.bookinfo_set.first().bookName)
# 显示这个类别下的所有数据,返回的结果是一个QuerySet数据集,这个类型下有两条数据,
print(bookType.bookinfo_set.all())
# 把QuerySet这个数据集转发到页面上就可以进行遍历了
content_value = {"title": "图书列表", "bookList": bookType.bookinfo_set.all()}
return render(request, 'book/list.html', context=content_value)
def preAdd(request):
"""
预处理,添加操作
:param request:
:return:
"""
# 预处理操作需要先找到所有数据
bookTypeList = BookTypeInfo.objects.all()
print(f'可自行打印查看bookTypeList是否查询出所有数据:{bookTypeList}')
# 预处理操作之后要返回到图书添加页面
content_value = {"title": "图书添加", "bookTypeList": bookTypeList}
return render(request, 'book/add.html', context=content_value)
def preAdd2(request):
"""
预处理,添加操作 使用form表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoForm
form = BookInfoForm()
context_value = {"title": "图书添加2", "form": form}
return render(request, 'book/add2.html', context_value)
def preAdd3(request):
"""
预处理,添加操作 使用ModelForm表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoModelForm
form = BookInfoModelForm()
context_value = {"title": "图书添加3", "form": form}
return render(request, 'book/add3.html', context_value)
def add(request):
"""
图书添加
:param request:
:return:
"""
# 封装对象
book = BookInfo()
# 添加数据
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType")
book.price = request.POST.get("price")
# 因为是模板,所以直接使用save()方法
book.save()
# 数据添加完成之后,可以获取新增数据的主键id
print(f'数据添加完成之后,获取新增数据的主键id:{book.id}')
# 添加完成之后,需要返回到列表,直接return返回那个对象
return bookList(request)
# 修改预处理,定义修改操作方法;页面需要传一个id来确定是要修改哪一条记录
def preUpdate(request, id):
"""
预处理,修改操作
:param request:
:return:
"""
print("通过path里面的变量,页面需要传一个id来确定是要修改哪一条记录:", id)
# 根据传过来的id去查询数据,并返回一个book对象
book = BookInfo.objects.get(id=id)
print(f'可自行打印查看返回的book对象:{book}')
bookTypeList = BookTypeInfo.objects.all()
print(bookTypeList)
# book对象也需要传到页面上去,到时候页面上就能够取值了
content_value = {"title": "图书修改", "bookTypeList": bookTypeList, "book": book}
return render(request, 'book/edit.html', context=content_value)
def update(request):
"""
图书修改
:param request:
:return:
"""
book = BookInfo()
book.id = request.POST.get("id")
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType_id")
book.price = request.POST.get("price")
book.save()
return bookList(request)
def delete(request, id):
"""
图书删除
:param request:
:return:
"""
# 删除指定id数据
BookInfo.objects.get(id=id).delete()
# 根据条件删除多条数据
# BookInfo.objects.filter(price__gte=100).delete()
# 删除所有数据
# BookInfo.objects.all().delete()
return bookList(request)
# 定义转账transfer方法--导包引入from django.db import transaction模块使用事务
@transaction.atomic
def transfer(request):
"""
模拟转账
:param request:
:return:
"""
# 开启事务,
sid = transaction.savepoint()
# 添加异常处理机制
try:
# 导包引入from helloWorld.models import AccountInfo方法
# AccountInfo.objects.filter()方法查找A用户
a1 = AccountInfo.objects.filter(user='A用户_赵大')
# 导包引入from django.db.models import F 模块
a1.update(account = F('account') + 100)
# 这个"'A用户_赵大'"账户是加account余额,那么对应的"'B 用户_ 钱二'"账户就是减account余额
b2 = AccountInfo.objects.filter(user='B用户_钱二')
# 修改操作
b2.update(account = F('account') - 100 / 0)
# 提交事务,如果不设置,当程序执行完成后,会自动提交事务
transaction.savepoint_commit(sid)
except Exception as e:
print(f'异常信息为:{e}')
# 事务回滚--传一个sid表示需要事务回滚哪一个事务
transaction.savepoint_rollback(sid)
# 执行完两个操作之后,模拟转账完成,返回到界面
return HttpResponse("OK!转账完成!")
def to_register(request):
"""
跳转注册页面
:param request:
:return:
"""
return render(request, 'auth/register.html')
def register(request):
"""
用户注册
:param request:
:return:
"""
# 首先需要获取用户名密码参数
username = request.POST.get('username')
password = request.POST.get('password')
# 检验用户名是否存在
result = User.objects.filter(username=username)
if result:
return render(request, 'auth/register.html',
context={"errorInfo": "该用户名已存在", "username": username, "password": password})
# 导包引入from django.contrib.auth.models import User模型,使用封装好的create_user方法操作数据库
User.objects.create_user(username=username, password=password)
return render(request, "auth/login.html")

6、浏览器输入"http://127.0.0.1:8000/auth/toRegister"打开用户注册页面,输入相同的用户名(例如,用户名:dev01)后,点击"提交"按钮进行测试验证,查看到有提示和回显数据,表示功能已经成功生效。

用户登录实现
用户登录功能,后端验证主要通过 auth 模块提供的 authenticate 校验方法,以及login登录方法实现;主要是熟悉 auth 模块的常用方法;
7、修改"djangoProject"项目"templates"目录"auth"目录文件路径下的"login.html"文件内容,输入以下内容;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="/auth/logins" method="post">
{% csrf_token %}
<table>
<tr>
<th>用户登录</th>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" value="{{ username }}"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" value="{{ password }}"></td>
</tr>
<tr>
<td>
<input type="submit" value="提交">
</td>
<td>
<font color="red">{{ errorInfo }}</font>
</td>
</tr>
</table>
</form>
</body>
</html>

8、当登录验证成功之后跳转到一个"index(网站首页 index.html)"页面,在"djangoProject"项目"templates"目录"auth"目录文件路径下新建名称为"list"的 HTML 文件,输入以下内容;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>网站首页</title>
</head>
<body>
网站首页,欢迎: {{ request.user }}
</body>
</html>

9、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容,定义实现 to_logins 和 logins 两个方法;
# 导包
import datetime
import os
from django.contrib import auth
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db import connection, transaction
from django.db.backends.utils import CursorDebugWrapper
from django.db.models import Q, Sum, Avg, F
from django.http import HttpResponse, HttpResponseNotFound, JsonResponse, StreamingHttpResponse, FileResponse
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from helloWorld.forms import StudentForm, BookInfoForm, BookInfoModelForm
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo, AccountInfo
# Create your views here.
# 定义类
class Person:
# 属性 姓名
name = None
# 属性 年龄
age = None
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义一个index方法,里面要加上request请求对象
def index(request):
# 传递字符串类型数据,定义字符串类型变量str
str = 'hello world!'
# 日期对象date,导包引入import datetime
date = datetime.datetime.now()
# 定义字典类型数据
myDict = {"Jack":"11", "Queen":"12", "King":"13"}
# 创建一个对象,例如:zhangsan
zhangsan = Person("张三", 18)
# 定义列表myList、元组myTuple--列表和元组里面的元素类型没有限制,列表里面可以嵌套列表,元组里面可以嵌套元组
myList = [1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10}]
myTuple = (1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10})
# 变量content_value是字典格式
content_value = {"content_msg": str, "msg2": myDict, "msg3": zhangsan, "msg4": myList, "msg5": myTuple, "date": date}
# context= 传递的本身要求格式是一个字典类型
return render(request, 'index.html', context=content_value)
# 定义index_id方法,里面第一个参数request请求对象,第二个参数 id
def index_id(request, id):
# 判断 id是否为0
if id == 0:
# 导包引入redirect模块,如果id等于0的话,重定向到一个目标静态地址
return redirect("/static/error.html")
else:
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse("id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,里面继续跟多个路由变量"year, month, day, id"
def index_id02(request, year, month, day, id):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + "/" + str(month) + "/" + str(day) + "/" +"id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,后面跟多个路由变量"year, month, day"--注意,使用正则后不能与"id"再混合使用了
def index_id03(request, year, month, day):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + '/' + str(month) + '/' + str(day) + "使用正则路由后的某某平台系统页面")
# 定义目标文件路径
file_path = "D:\\works\\djangoProject\\datas\\IDM.rar"
# 定义download_file1下载方法,请求需要带上request(所有的请求都要带上request)
def download_file1(request):
# 定义文件--使用open函数方法以"rb"二进制读取模式打开文件--然后返回一个file文件对象
file = open(file_path, 'rb')
# 创建构造好了HttpResponse对象之后返回给response
response = HttpResponse(file)
# 指定文件类型
response['Content-Type'] = 'application/rar-compressed'
# 扩展--指定附件及文件名字(可以动态拼接filename,并不建议使用原始名称)
response['Content-Disposition'] = 'attachment; filename=file1.rar'
return response
def download_file2(request):
file = open(file_path, 'rb')
# 创建构造好了StreamingHttpResponse对象之后返回给response
response = StreamingHttpResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file2.rar'
return response
def download_file3(request):
file = open(file_path, 'rb')
# 创建构造好了FileResponse对象之后返回给response
response = FileResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file3.rar'
return response
def get_test(request):
"""
get 请求测试
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'打印常用属性request.content_type:{request.content_type}')
print(f'打印常用属性request.content_params:{request.content_params}')
print(f'打印常用属性request.COOKIES:{request.COOKIES}')
print(f'打印常用属性request.scheme:{request.scheme}')
print(f'打印常用方法request.is_secure:{request.is_secure()}')
print(f'打印常用方法request.get_host:{request.get_host()}')
print(f'打印常用方法request.get_full_path:{request.get_full_path()}')
print(f'使用request.GET.get("name")方法获取对应key值参数:{request.GET.get("name")}' )
print(f'使用request.GET.get("pwd")方法获取对应key值参数:{request.GET.get("pwd")}')
print(f'使用request.GET.get("dev")方法获取不存在的参数,返回值是'None':{request.GET.get("dev")}')
print(f'request.GET.get("prod", "555")获取的prod参数是不存在的,设置返回值'555':{request.GET.get("prod", "555")}')
return HttpResponse("hello world!http get ok!")
def post_test(request):
"""
post 请求测试方法
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'使用request.POST.get("name")方法获取对应key值参数:{request.POST.get("name")}')
print(f'使用request.POST.get("pwd")方法获取对应key值参数:{request.POST.get("pwd")}')
print(f'使用request.POST.get("dev")方法获取不存在的参数,返回值是'None':{request.POST.get("dev")}')
print(f'request.POST.get("prod", "556")获取的prod参数是不存在的,设置返回值'556':{request.POST.get("prod", "556")}')
return HttpResponse("hello world!http post ok!")
def to_login(request):
"""
跳转到登录页面
:param request:
:return:
"""
# 跳转到登录页面可直接使用渲染render()方法
return render(request, 'login.html')
def login(request):
"""
登录到主页面
:param request:
:return:
"""
# 首先获取用户名和密码
user_name = request.POST.get('user_name')
pwd = request.POST.get('pwd')
# 模拟用户登录(暂不连接数据库)
if user_name == "python3" and pwd == "123456":
# session中存一个用户名
request.session['currentUserName'] = user_name
print(f'代码脚本中session获取:{request.session['currentUserName']}')
# 获取HttpResponse
response = render(request, 'main.html')
# 通过response.set_Cookie()方法来设置cookie
response.set_cookie('remember_me', True)
return response
else:
# 定义变量content_value为报错提示信息,里面是键值对格式的对象
content_value = {"error_info":"用户名或者密码错误!"}
return render(request, 'login.html', context=content_value)
def to_upload(request):
"""
跳转到上传文件页面
:param request:
:return:
"""
return render(request, 'upload.html')
def upload(request):
"""
上传文件处理
:param request:
:return:
"""
# 获取上传的文件,如果没有文件,就默认为None(如果不写指定的None,也是默认None)
myFile = request.FILES.get("myfile", None)
# 判断如果是有myFile的情况,就是说明有文件
if myFile:
# 打开特定的文件进行二进制的写操作--上传文件路径烦请自行创建(例如:在项目datas路径下新建"myFile"目录文件)
f = open(os.path.join("D:\\works\\djangoProject\\datas\\myFile", myFile.name), "wb+")
# 分块写入文件
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("文件上传成功!")
else:
return HttpResponse("没有发现可以上传的文件!")
# 定义List类,继续继承ListView(导包引入 from django.views.generic import ListView)
class List(ListView):
# 设置模版文件
template_name = 'student/list.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息列表'}
# 定义数据集(查询结果集)--StudentInfo(导入 from helloWorld.models import StudentInfo)
queryset = StudentInfo.objects.all()
# 每页展示数据的条数(自行设置)
paginate_by = 5
# 设置上下文对象名称(其实就是一个列表的对象),建议使用自定义名称,不然就默认为 objectlist
context_object_name = 'student_list'
# 定义Detail类,继续继承DetailView(导包引入 from django.views.generic import DetailView)
class Detail(DetailView):
# 设置模版文件
template_name = 'student/detail.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息详情'}
# 设置查询模型--指定model(不然无法查询数据)
model = StudentInfo
# 设置上下文对象名称
context_object_name = 'student'
# 指定URL中用于获取对象的唯一标识符的参数名称,默认为'pk';
# 如若在urls.py文件中自定义了名称,则需要添加对应pk_url_kwarg参数为自定义名称
# pk_url_kwarg = 'id'
# 定义Create类,继续继承CreateView(导包引入 from django.views.generic import CreateView)
class Create(CreateView):
# 设置模版文件,名称修改为create(有的名称叫"add"也行)
template_name = 'student/create.html'
# 设置模型外的数据--例如:指定标题"添加"或者"新增"都行
extra_context = {'title': '学生信息新增'}
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Update类,继续继承UpdateView(导包引入 from django.views.generic import UpdateView)
class Update(UpdateView):
# 设置模版文件,名称修改为update(自定义)
template_name = 'student/update.html'
# 设置模型外的数据--例如:指定标题"编辑"或者"修改"都行
extra_context = {'title': '学生信息编辑'}
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Delete类,继续继承DeleteView(导包引入 from django.views.generic import DeleteView)
class Delete(DeleteView):
# 设置模版文件,名称修改为delete(自定义)
template_name = 'student/delete.html'
# 设置模型外的数据--例如:指定标题"删除"或者"修改"都行
extra_context = {'title': '学生信息删除'}
# 设置上下文对象名称
context_object_name = 'student'
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 自定义跳转子类模板页面方法
def to_course(request):
"""
跳转到子类模板页面
:param request:
:return:
"""
return render(request, 'course.html')
# 定义bookList方法
def bookList(request):
"""
图书列表查询
"""
# 查询显示所有数据
bookList = BookInfo.objects.all()
# 使用BookInfo.objects.extra()方法,里面使用where加参数(元组格式),在params加上具体的参数,也是一个元组
# 如果是模型外的参数(models.py里面没有定义的参数),可以使用BookInfo.objects.select()方法
# bookList = BookInfo.objects.extra(where=["price>%s"], params=[90])
# # 使用BookInfo.objects.raw()方法,直接写一个SQL语句
# bookList = BookInfo.objects.raw('SELECT * FROM t_book where price>%s', params=[90])
# 使用connection方法需要导包引入from django.db import connection模块,返回一个cursor游标
# 指定cursor游标为CursorDebugWrapper类型,需导包引入from django.db.backends.utils import CursorDebugWrapper模块
cursor: CursorDebugWrapper = connection.cursor()
# 然后就可以执行使用execute方法,查询图书价格大于90的记录数
# cursor.execute('select count(*) from t_book where price>90')
# print('预计提取的一个结果是(2,):', cursor.fetchone())
content_value = {"title": "图书列表", "bookList": bookList}
return render(request, 'book/list.html', context=content_value)
def bookList2(request):
"""
多表查询,有正向查询和反向查询
:param request:
:return:
"""
# 正向查询(经常使用)--多的一端BookInfo条件id=2且只查询一条数据,返回图书book并指定类型BookInfo
book: BookInfo = BookInfo.objects.filter(id=2).first()
# 能够输出book的所有信息,也能输出所关联的bookType.bookTypeName数据信息
print(book.bookName, book.bookType.bookTypeName)
# 反向查询(很少使用)--(导包引入from helloWorld.models import BookTypeInfo)
# 一的一端BookTypeInfo条件id=1且只查询一条数据,返回图书类别bookType并指定类型BookTypeInfo
bookType: BookTypeInfo = BookTypeInfo.objects.filter(id=1).first()
# 输出读取关联的这个图书类别下的所有图书的数据集中第一条数据,固定语法bookinfo_set
print(bookType.bookinfo_set.first().bookName)
# 显示这个类别下的所有数据,返回的结果是一个QuerySet数据集,这个类型下有两条数据,
print(bookType.bookinfo_set.all())
# 把QuerySet这个数据集转发到页面上就可以进行遍历了
content_value = {"title": "图书列表", "bookList": bookType.bookinfo_set.all()}
return render(request, 'book/list.html', context=content_value)
def preAdd(request):
"""
预处理,添加操作
:param request:
:return:
"""
# 预处理操作需要先找到所有数据
bookTypeList = BookTypeInfo.objects.all()
print(f'可自行打印查看bookTypeList是否查询出所有数据:{bookTypeList}')
# 预处理操作之后要返回到图书添加页面
content_value = {"title": "图书添加", "bookTypeList": bookTypeList}
return render(request, 'book/add.html', context=content_value)
def preAdd2(request):
"""
预处理,添加操作 使用form表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoForm
form = BookInfoForm()
context_value = {"title": "图书添加2", "form": form}
return render(request, 'book/add2.html', context_value)
def preAdd3(request):
"""
预处理,添加操作 使用ModelForm表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoModelForm
form = BookInfoModelForm()
context_value = {"title": "图书添加3", "form": form}
return render(request, 'book/add3.html', context_value)
def add(request):
"""
图书添加
:param request:
:return:
"""
# 封装对象
book = BookInfo()
# 添加数据
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType")
book.price = request.POST.get("price")
# 因为是模板,所以直接使用save()方法
book.save()
# 数据添加完成之后,可以获取新增数据的主键id
print(f'数据添加完成之后,获取新增数据的主键id:{book.id}')
# 添加完成之后,需要返回到列表,直接return返回那个对象
return bookList(request)
# 修改预处理,定义修改操作方法;页面需要传一个id来确定是要修改哪一条记录
def preUpdate(request, id):
"""
预处理,修改操作
:param request:
:return:
"""
print("通过path里面的变量,页面需要传一个id来确定是要修改哪一条记录:", id)
# 根据传过来的id去查询数据,并返回一个book对象
book = BookInfo.objects.get(id=id)
print(f'可自行打印查看返回的book对象:{book}')
bookTypeList = BookTypeInfo.objects.all()
print(bookTypeList)
# book对象也需要传到页面上去,到时候页面上就能够取值了
content_value = {"title": "图书修改", "bookTypeList": bookTypeList, "book": book}
return render(request, 'book/edit.html', context=content_value)
def update(request):
"""
图书修改
:param request:
:return:
"""
book = BookInfo()
book.id = request.POST.get("id")
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType_id")
book.price = request.POST.get("price")
book.save()
return bookList(request)
def delete(request, id):
"""
图书删除
:param request:
:return:
"""
# 删除指定id数据
BookInfo.objects.get(id=id).delete()
# 根据条件删除多条数据
# BookInfo.objects.filter(price__gte=100).delete()
# 删除所有数据
# BookInfo.objects.all().delete()
return bookList(request)
# 定义转账transfer方法--导包引入from django.db import transaction模块使用事务
@transaction.atomic
def transfer(request):
"""
模拟转账
:param request:
:return:
"""
# 开启事务,
sid = transaction.savepoint()
# 添加异常处理机制
try:
# 导包引入from helloWorld.models import AccountInfo方法
# AccountInfo.objects.filter()方法查找A用户
a1 = AccountInfo.objects.filter(user='A用户_赵大')
# 导包引入from django.db.models import F 模块
a1.update(account = F('account') + 100)
# 这个"'A用户_赵大'"账户是加account余额,那么对应的"'B 用户_ 钱二'"账户就是减account余额
b2 = AccountInfo.objects.filter(user='B用户_钱二')
# 修改操作
b2.update(account = F('account') - 100 / 0)
# 提交事务,如果不设置,当程序执行完成后,会自动提交事务
transaction.savepoint_commit(sid)
except Exception as e:
print(f'异常信息为:{e}')
# 事务回滚--传一个sid表示需要事务回滚哪一个事务
transaction.savepoint_rollback(sid)
# 执行完两个操作之后,模拟转账完成,返回到界面
return HttpResponse("OK!转账完成!")
def to_register(request):
"""
跳转注册页面
:param request:
:return:
"""
return render(request, 'auth/register.html')
def register(request):
"""
用户注册
:param request:
:return:
"""
# 首先需要获取用户名密码参数
username = request.POST.get('username')
password = request.POST.get('password')
# 检验用户名是否存在
result = User.objects.filter(username=username)
if result:
return render(request, 'auth/register.html',
context={"errorInfo": "该用户名已存在", "username": username, "password": password})
# 导包引入from django.contrib.auth.models import User模型,使用封装好的create_user方法操作数据库
User.objects.create_user(username=username, password=password)
return render(request, "auth/login.html")
def to_logins(request):
"""
跳转登录页面
:param request:
:return:
"""
return render(request, 'auth/login.html')
def logins(request):
"""
登录处理
:param request:
:return:
"""
username = request.POST.get('username')
password = request.POST.get('password')
# 导包引入from django.contrib import auth模块,通过auth模块authenticate验证方法来验证,验证方法里面要传入用户名和密码
# authenticate验证方法的第一个参数要的是request,然后是username、password
# 如果验证成功了,校验成功返回用户对象,如果不存在则返回None;指定一个类型去接收返回的用户对象
resUser: User = auth.authenticate(request, username=username, password=password)
print(f'打印查看resUser:{resUser},查看resUser类型:{type(resUser)}')
# 如果存在resUser这个用户 并且使用is_active方法判断用户对象在数据库中是否激活
if resUser and resUser.is_active:
# 用户登录成功之后(返回给客户端登录的凭证或者说是令牌、随机字符串)
auth.login(request, resUser)
return render(request, 'auth/index.html')
else:
return render(request, 'auth/login.html',
context={"errorInfo": "用户名或者密码错误", "username": username, "password": password})

10、修改"djangoProject"应用下的"urls.py"配置文件内容,配置定义映射关系;
"""
URL configuration for djangoProject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.contrib import admin
from django.urls import path, re_path, include
from django.views.generic import RedirectView
from django.views.static import serve
import helloWorld.views
urlpatterns = [
path('admin/', admin.site.urls),
# 可直接复制上面"admin",把"admin"修改为"index";后面是跟的"处理函数helloWorld.views.index"
# 是helloWorld应用的views里面的index()--引入helloWorld.views,记得index后不能加小括号,因为传入的是对象;
path('index/', helloWorld.views.index, name='index'),
# 要是请求"redirectTo"这个请求的话给重定向到"index"--重定向使用RedirectView.as_view(),里面使用关键词参数url
path('redirectTo', RedirectView.as_view(url="index/")),
# 自定义名称,例如叫"index_id/",后面再跟上某网页id;<int:id> int指定类型,路由变量为id;对应对应的路由映射
path('index_id/<int:id>', helloWorld.views.index_id),
# 多个路由变量
path('index_id02/<int:year>/<int:month>/<int:day>/<int:id>', helloWorld.views.index_id02),
# 正则表达式匹配是必须使用re_path方法,正则表达式"?P"开头是固定格式
re_path('index_id03/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})', helloWorld.views.index_id03),
# 配置媒体文件的路由地址
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 命名空间namespace--比如说是"user/"开头的,第一个参数include(),第二个参数namespace
# 导包引入include模块,include()里面也有两个参数,第一个是指定user的urls,第二个是项目名;
path('user/', include(('user.urls', 'user'), namespace='user')),
path('order/', include(('order.urls', 'order'), namespace='order')),
# 配置 download_file
path('download1/', helloWorld.views.download_file1),
path('download2/', helloWorld.views.download_file2),
path('download3/', helloWorld.views.download_file3),
path('get', helloWorld.views.get_test),
path('post', helloWorld.views.post_test),
path('toLogin/', helloWorld.views.to_login),
path('login', helloWorld.views.login),
path('toUpload/', helloWorld.views.to_upload),
path('upload', helloWorld.views.upload),
path('student/list', helloWorld.views.List.as_view()),
# 默认名称就是"pk",建议不要更改,在开发过程中就默认为pk即可
path('student/<int:pk>', helloWorld.views.Detail.as_view()),
# 如果把默认名称"pk"更改为其他(例如:id),则需要在urls.py配置文件Detail类中添加pk_url_kwarg参数
# path('student/<int:id>', helloWorld.views.Detail.as_view())
path('student/create', helloWorld.views.Create.as_view()),
path('student/update/<int:pk>', helloWorld.views.Update.as_view()),
path('student/delete/<int:pk>', helloWorld.views.Delete.as_view()),
path('toCourse/', helloWorld.views.to_course),
path('book/list', helloWorld.views.bookList),
path('book/list2', helloWorld.views.bookList2),
path('book/preAdd', helloWorld.views.preAdd),
path('book/add', helloWorld.views.add),
path('book/preUpdate/<int:id>', helloWorld.views.preUpdate),
path('book/delete/<int:id>', helloWorld.views.delete),
path('book/update', helloWorld.views.update),
path('transfer/', helloWorld.views.transfer),
path('book/preAdd2', helloWorld.views.preAdd2),
path('book/preAdd3', helloWorld.views.preAdd3),
# 跳转注册页面
path('auth/toRegister', helloWorld.views.to_register),
# 提交注册请求
path('auth/register', helloWorld.views.register),
# 跳转登录页面
path('auth/toLogins', helloWorld.views.to_logins),
# 提交登录请求
path('auth/logins', helloWorld.views.logins)
]

11、运行项目,浏览器输入"http://127.0.0.1:8000/auth/toLogins"测试验证,分别输入注册过的正确用户名(dev01)密码(123)和不正确的账号密码,用户名密码输入错误,提示报错信息,用户名密码输入正确,则跳转到设置的网站首页。

通过 auth.authenticate 校验用户是否已经存在,相当于一个验证方法;校验用户成功后,它会有个返回值是一个封装好的用户对象,否则的话校验错误返回None;然后判断这个用户是否存在并且使用 is_active方法判断用户对象在数据库中是否激活;通过调用auth.login,用户登录成功之后,返回给客户端登录的凭证或者说是令牌、随机字符串,则不需要手动去操作diango_session 表,会自动创建 session;

当执行完
auth.authenticate和auth.login后,也就是登录成功后,就可以通过request.user直接获取到当前登录的用户对象数据;
- 登录成功的情况下,该方法获得的是登录用户对象;
- 登录不成功的情况下,该方法获得的是匿名对象
AnonymousUser,其实就是登录没成功;用户修改密码实现
用户修改密码主要是通过 request.user 对象(也就是模型)的 set_password 实现,当然在修改密码之前还需要校验原密码用 check_password,设置完后,需要保存,调用 save() 方法;
12、在"djangoProject"项目"templates"目录"auth"目录文件路径下新建名称为"setPwd"的 HTML 文件,输入以下内容;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>修改密码</title>
</head>
<body>
<form action="/auth/setPwd" method="post">
{% csrf_token %}
<table>
<tr>
<th>修改密码</th>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" value="{{ request.user }}" readonly></td>
</tr>
<tr>
<td>原密码:</td>
<td><input type="password" name="oldPwd" value="{{ oldPwd }}"></td>
</tr>
<tr>
<td>新密码:</td>
<td><input type="password" name="newPwd" value="{{ newPwd }}"></td>
</tr>
<tr>
<td>
<input type="submit" value="提交">
</td>
<td>
<font color="red">{{ errorInfo }}</font>
</td>
</tr>
</table>
</form>
</body>
</html>

13、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容,定义实现 setPwd函数;
# 导包
import datetime
import os
from django.contrib import auth
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db import connection, transaction
from django.db.backends.utils import CursorDebugWrapper
from django.db.models import Q, Sum, Avg, F
from django.http import HttpResponse, HttpResponseNotFound, JsonResponse, StreamingHttpResponse, FileResponse
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from helloWorld.forms import StudentForm, BookInfoForm, BookInfoModelForm
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo, AccountInfo
# Create your views here.
# 定义类
class Person:
# 属性 姓名
name = None
# 属性 年龄
age = None
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义一个index方法,里面要加上request请求对象
def index(request):
# 传递字符串类型数据,定义字符串类型变量str
str = 'hello world!'
# 日期对象date,导包引入import datetime
date = datetime.datetime.now()
# 定义字典类型数据
myDict = {"Jack":"11", "Queen":"12", "King":"13"}
# 创建一个对象,例如:zhangsan
zhangsan = Person("张三", 18)
# 定义列表myList、元组myTuple--列表和元组里面的元素类型没有限制,列表里面可以嵌套列表,元组里面可以嵌套元组
myList = [1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10}]
myTuple = (1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10})
# 变量content_value是字典格式
content_value = {"content_msg": str, "msg2": myDict, "msg3": zhangsan, "msg4": myList, "msg5": myTuple, "date": date}
# context= 传递的本身要求格式是一个字典类型
return render(request, 'index.html', context=content_value)
# 定义index_id方法,里面第一个参数request请求对象,第二个参数 id
def index_id(request, id):
# 判断 id是否为0
if id == 0:
# 导包引入redirect模块,如果id等于0的话,重定向到一个目标静态地址
return redirect("/static/error.html")
else:
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse("id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,里面继续跟多个路由变量"year, month, day, id"
def index_id02(request, year, month, day, id):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + "/" + str(month) + "/" + str(day) + "/" +"id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,后面跟多个路由变量"year, month, day"--注意,使用正则后不能与"id"再混合使用了
def index_id03(request, year, month, day):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + '/' + str(month) + '/' + str(day) + "使用正则路由后的某某平台系统页面")
# 定义目标文件路径
file_path = "D:\\works\\djangoProject\\datas\\IDM.rar"
# 定义download_file1下载方法,请求需要带上request(所有的请求都要带上request)
def download_file1(request):
# 定义文件--使用open函数方法以"rb"二进制读取模式打开文件--然后返回一个file文件对象
file = open(file_path, 'rb')
# 创建构造好了HttpResponse对象之后返回给response
response = HttpResponse(file)
# 指定文件类型
response['Content-Type'] = 'application/rar-compressed'
# 扩展--指定附件及文件名字(可以动态拼接filename,并不建议使用原始名称)
response['Content-Disposition'] = 'attachment; filename=file1.rar'
return response
def download_file2(request):
file = open(file_path, 'rb')
# 创建构造好了StreamingHttpResponse对象之后返回给response
response = StreamingHttpResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file2.rar'
return response
def download_file3(request):
file = open(file_path, 'rb')
# 创建构造好了FileResponse对象之后返回给response
response = FileResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file3.rar'
return response
def get_test(request):
"""
get 请求测试
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'打印常用属性request.content_type:{request.content_type}')
print(f'打印常用属性request.content_params:{request.content_params}')
print(f'打印常用属性request.COOKIES:{request.COOKIES}')
print(f'打印常用属性request.scheme:{request.scheme}')
print(f'打印常用方法request.is_secure:{request.is_secure()}')
print(f'打印常用方法request.get_host:{request.get_host()}')
print(f'打印常用方法request.get_full_path:{request.get_full_path()}')
print(f'使用request.GET.get("name")方法获取对应key值参数:{request.GET.get("name")}' )
print(f'使用request.GET.get("pwd")方法获取对应key值参数:{request.GET.get("pwd")}')
print(f'使用request.GET.get("dev")方法获取不存在的参数,返回值是'None':{request.GET.get("dev")}')
print(f'request.GET.get("prod", "555")获取的prod参数是不存在的,设置返回值'555':{request.GET.get("prod", "555")}')
return HttpResponse("hello world!http get ok!")
def post_test(request):
"""
post 请求测试方法
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'使用request.POST.get("name")方法获取对应key值参数:{request.POST.get("name")}')
print(f'使用request.POST.get("pwd")方法获取对应key值参数:{request.POST.get("pwd")}')
print(f'使用request.POST.get("dev")方法获取不存在的参数,返回值是'None':{request.POST.get("dev")}')
print(f'request.POST.get("prod", "556")获取的prod参数是不存在的,设置返回值'556':{request.POST.get("prod", "556")}')
return HttpResponse("hello world!http post ok!")
def to_login(request):
"""
跳转到登录页面
:param request:
:return:
"""
# 跳转到登录页面可直接使用渲染render()方法
return render(request, 'login.html')
def login(request):
"""
登录到主页面
:param request:
:return:
"""
# 首先获取用户名和密码
user_name = request.POST.get('user_name')
pwd = request.POST.get('pwd')
# 模拟用户登录(暂不连接数据库)
if user_name == "python3" and pwd == "123456":
# session中存一个用户名
request.session['currentUserName'] = user_name
print(f'代码脚本中session获取:{request.session['currentUserName']}')
# 获取HttpResponse
response = render(request, 'main.html')
# 通过response.set_Cookie()方法来设置cookie
response.set_cookie('remember_me', True)
return response
else:
# 定义变量content_value为报错提示信息,里面是键值对格式的对象
content_value = {"error_info":"用户名或者密码错误!"}
return render(request, 'login.html', context=content_value)
def to_upload(request):
"""
跳转到上传文件页面
:param request:
:return:
"""
return render(request, 'upload.html')
def upload(request):
"""
上传文件处理
:param request:
:return:
"""
# 获取上传的文件,如果没有文件,就默认为None(如果不写指定的None,也是默认None)
myFile = request.FILES.get("myfile", None)
# 判断如果是有myFile的情况,就是说明有文件
if myFile:
# 打开特定的文件进行二进制的写操作--上传文件路径烦请自行创建(例如:在项目datas路径下新建"myFile"目录文件)
f = open(os.path.join("D:\\works\\djangoProject\\datas\\myFile", myFile.name), "wb+")
# 分块写入文件
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("文件上传成功!")
else:
return HttpResponse("没有发现可以上传的文件!")
# 定义List类,继续继承ListView(导包引入 from django.views.generic import ListView)
class List(ListView):
# 设置模版文件
template_name = 'student/list.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息列表'}
# 定义数据集(查询结果集)--StudentInfo(导入 from helloWorld.models import StudentInfo)
queryset = StudentInfo.objects.all()
# 每页展示数据的条数(自行设置)
paginate_by = 5
# 设置上下文对象名称(其实就是一个列表的对象),建议使用自定义名称,不然就默认为 objectlist
context_object_name = 'student_list'
# 定义Detail类,继续继承DetailView(导包引入 from django.views.generic import DetailView)
class Detail(DetailView):
# 设置模版文件
template_name = 'student/detail.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息详情'}
# 设置查询模型--指定model(不然无法查询数据)
model = StudentInfo
# 设置上下文对象名称
context_object_name = 'student'
# 指定URL中用于获取对象的唯一标识符的参数名称,默认为'pk';
# 如若在urls.py文件中自定义了名称,则需要添加对应pk_url_kwarg参数为自定义名称
# pk_url_kwarg = 'id'
# 定义Create类,继续继承CreateView(导包引入 from django.views.generic import CreateView)
class Create(CreateView):
# 设置模版文件,名称修改为create(有的名称叫"add"也行)
template_name = 'student/create.html'
# 设置模型外的数据--例如:指定标题"添加"或者"新增"都行
extra_context = {'title': '学生信息新增'}
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Update类,继续继承UpdateView(导包引入 from django.views.generic import UpdateView)
class Update(UpdateView):
# 设置模版文件,名称修改为update(自定义)
template_name = 'student/update.html'
# 设置模型外的数据--例如:指定标题"编辑"或者"修改"都行
extra_context = {'title': '学生信息编辑'}
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Delete类,继续继承DeleteView(导包引入 from django.views.generic import DeleteView)
class Delete(DeleteView):
# 设置模版文件,名称修改为delete(自定义)
template_name = 'student/delete.html'
# 设置模型外的数据--例如:指定标题"删除"或者"修改"都行
extra_context = {'title': '学生信息删除'}
# 设置上下文对象名称
context_object_name = 'student'
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 自定义跳转子类模板页面方法
def to_course(request):
"""
跳转到子类模板页面
:param request:
:return:
"""
return render(request, 'course.html')
# 定义bookList方法
def bookList(request):
"""
图书列表查询
"""
# 查询显示所有数据
bookList = BookInfo.objects.all()
# 使用BookInfo.objects.extra()方法,里面使用where加参数(元组格式),在params加上具体的参数,也是一个元组
# 如果是模型外的参数(models.py里面没有定义的参数),可以使用BookInfo.objects.select()方法
# bookList = BookInfo.objects.extra(where=["price>%s"], params=[90])
# # 使用BookInfo.objects.raw()方法,直接写一个SQL语句
# bookList = BookInfo.objects.raw('SELECT * FROM t_book where price>%s', params=[90])
# 使用connection方法需要导包引入from django.db import connection模块,返回一个cursor游标
# 指定cursor游标为CursorDebugWrapper类型,需导包引入from django.db.backends.utils import CursorDebugWrapper模块
cursor: CursorDebugWrapper = connection.cursor()
# 然后就可以执行使用execute方法,查询图书价格大于90的记录数
# cursor.execute('select count(*) from t_book where price>90')
# print('预计提取的一个结果是(2,):', cursor.fetchone())
content_value = {"title": "图书列表", "bookList": bookList}
return render(request, 'book/list.html', context=content_value)
def bookList2(request):
"""
多表查询,有正向查询和反向查询
:param request:
:return:
"""
# 正向查询(经常使用)--多的一端BookInfo条件id=2且只查询一条数据,返回图书book并指定类型BookInfo
book: BookInfo = BookInfo.objects.filter(id=2).first()
# 能够输出book的所有信息,也能输出所关联的bookType.bookTypeName数据信息
print(book.bookName, book.bookType.bookTypeName)
# 反向查询(很少使用)--(导包引入from helloWorld.models import BookTypeInfo)
# 一的一端BookTypeInfo条件id=1且只查询一条数据,返回图书类别bookType并指定类型BookTypeInfo
bookType: BookTypeInfo = BookTypeInfo.objects.filter(id=1).first()
# 输出读取关联的这个图书类别下的所有图书的数据集中第一条数据,固定语法bookinfo_set
print(bookType.bookinfo_set.first().bookName)
# 显示这个类别下的所有数据,返回的结果是一个QuerySet数据集,这个类型下有两条数据,
print(bookType.bookinfo_set.all())
# 把QuerySet这个数据集转发到页面上就可以进行遍历了
content_value = {"title": "图书列表", "bookList": bookType.bookinfo_set.all()}
return render(request, 'book/list.html', context=content_value)
def preAdd(request):
"""
预处理,添加操作
:param request:
:return:
"""
# 预处理操作需要先找到所有数据
bookTypeList = BookTypeInfo.objects.all()
print(f'可自行打印查看bookTypeList是否查询出所有数据:{bookTypeList}')
# 预处理操作之后要返回到图书添加页面
content_value = {"title": "图书添加", "bookTypeList": bookTypeList}
return render(request, 'book/add.html', context=content_value)
def preAdd2(request):
"""
预处理,添加操作 使用form表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoForm
form = BookInfoForm()
context_value = {"title": "图书添加2", "form": form}
return render(request, 'book/add2.html', context_value)
def preAdd3(request):
"""
预处理,添加操作 使用ModelForm表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoModelForm
form = BookInfoModelForm()
context_value = {"title": "图书添加3", "form": form}
return render(request, 'book/add3.html', context_value)
def add(request):
"""
图书添加
:param request:
:return:
"""
# 封装对象
book = BookInfo()
# 添加数据
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType")
book.price = request.POST.get("price")
# 因为是模板,所以直接使用save()方法
book.save()
# 数据添加完成之后,可以获取新增数据的主键id
print(f'数据添加完成之后,获取新增数据的主键id:{book.id}')
# 添加完成之后,需要返回到列表,直接return返回那个对象
return bookList(request)
# 修改预处理,定义修改操作方法;页面需要传一个id来确定是要修改哪一条记录
def preUpdate(request, id):
"""
预处理,修改操作
:param request:
:return:
"""
print("通过path里面的变量,页面需要传一个id来确定是要修改哪一条记录:", id)
# 根据传过来的id去查询数据,并返回一个book对象
book = BookInfo.objects.get(id=id)
print(f'可自行打印查看返回的book对象:{book}')
bookTypeList = BookTypeInfo.objects.all()
print(bookTypeList)
# book对象也需要传到页面上去,到时候页面上就能够取值了
content_value = {"title": "图书修改", "bookTypeList": bookTypeList, "book": book}
return render(request, 'book/edit.html', context=content_value)
def update(request):
"""
图书修改
:param request:
:return:
"""
book = BookInfo()
book.id = request.POST.get("id")
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType_id")
book.price = request.POST.get("price")
book.save()
return bookList(request)
def delete(request, id):
"""
图书删除
:param request:
:return:
"""
# 删除指定id数据
BookInfo.objects.get(id=id).delete()
# 根据条件删除多条数据
# BookInfo.objects.filter(price__gte=100).delete()
# 删除所有数据
# BookInfo.objects.all().delete()
return bookList(request)
# 定义转账transfer方法--导包引入from django.db import transaction模块使用事务
@transaction.atomic
def transfer(request):
"""
模拟转账
:param request:
:return:
"""
# 开启事务,
sid = transaction.savepoint()
# 添加异常处理机制
try:
# 导包引入from helloWorld.models import AccountInfo方法
# AccountInfo.objects.filter()方法查找A用户
a1 = AccountInfo.objects.filter(user='A用户_赵大')
# 导包引入from django.db.models import F 模块
a1.update(account = F('account') + 100)
# 这个"'A用户_赵大'"账户是加account余额,那么对应的"'B 用户_ 钱二'"账户就是减account余额
b2 = AccountInfo.objects.filter(user='B用户_钱二')
# 修改操作
b2.update(account = F('account') - 100 / 0)
# 提交事务,如果不设置,当程序执行完成后,会自动提交事务
transaction.savepoint_commit(sid)
except Exception as e:
print(f'异常信息为:{e}')
# 事务回滚--传一个sid表示需要事务回滚哪一个事务
transaction.savepoint_rollback(sid)
# 执行完两个操作之后,模拟转账完成,返回到界面
return HttpResponse("OK!转账完成!")
def to_register(request):
"""
跳转注册页面
:param request:
:return:
"""
return render(request, 'auth/register.html')
def register(request):
"""
用户注册
:param request:
:return:
"""
# 首先需要获取用户名密码参数
username = request.POST.get('username')
password = request.POST.get('password')
# 检验用户名是否存在
result = User.objects.filter(username=username)
if result:
return render(request, 'auth/register.html',
context={"errorInfo": "该用户名已存在", "username": username, "password": password})
# 导包引入from django.contrib.auth.models import User模型,使用封装好的create_user方法操作数据库
User.objects.create_user(username=username, password=password)
return render(request, "auth/login.html")
def to_logins(request):
"""
跳转登录页面
:param request:
:return:
"""
return render(request, 'auth/login.html')
def logins(request):
"""
登录处理
:param request:
:return:
"""
username = request.POST.get('username')
password = request.POST.get('password')
# 导包引入from django.contrib import auth模块,通过auth模块authenticate验证方法来验证,验证方法里面要传入用户名和密码
# authenticate验证方法的第一个参数要的是request,然后是username、password
# 如果验证成功了,校验成功返回用户对象,如果不存在则返回None;指定一个类型去接收返回的用户对象
resUser: User = auth.authenticate(request, username=username, password=password)
print(f'打印查看resUser:{resUser},查看resUser类型:{type(resUser)}')
# 如果存在resUser这个用户 并且使用is_active方法判断用户对象在数据库中是否激活
if resUser and resUser.is_active:
# 用户登录成功之后(返回给客户端登录的凭证或者说是令牌、随机字符串)
auth.login(request, resUser)
return render(request, 'auth/index.html')
else:
return render(request, 'auth/login.html',
context={"errorInfo": "用户名或者密码错误", "username": username, "password": password})
def setPwd(request):
"""
修改密码
:param request:
:return:
"""
if request.method == "POST":
oldPwd = request.POST.get("oldPwd")
newPwd = request.POST.get("newPwd")
# 1、校验用户密码(原密码) check_password
isRight = request.user.check_password(oldPwd)
if not isRight:
return render(request, 'auth/setPwd.html',
context={"errorInfo": "原密码错误!", "oldPwd": oldPwd, "newPwd": newPwd})
# 2、设置新密码 set_password 里面实现了加密
request.user.set_password(newPwd)
# 3、保存用户信息
request.user.save()
return render(request, 'auth/index.html')
return render(request, "auth/setPwd.html")

14、修改"djangoProject"应用下的"urls.py"配置文件内容,配置定义映射关系;
"""
URL configuration for djangoProject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.contrib import admin
from django.urls import path, re_path, include
from django.views.generic import RedirectView
from django.views.static import serve
import helloWorld.views
urlpatterns = [
path('admin/', admin.site.urls),
# 可直接复制上面"admin",把"admin"修改为"index";后面是跟的"处理函数helloWorld.views.index"
# 是helloWorld应用的views里面的index()--引入helloWorld.views,记得index后不能加小括号,因为传入的是对象;
path('index/', helloWorld.views.index, name='index'),
# 要是请求"redirectTo"这个请求的话给重定向到"index"--重定向使用RedirectView.as_view(),里面使用关键词参数url
path('redirectTo', RedirectView.as_view(url="index/")),
# 自定义名称,例如叫"index_id/",后面再跟上某网页id;<int:id> int指定类型,路由变量为id;对应对应的路由映射
path('index_id/<int:id>', helloWorld.views.index_id),
# 多个路由变量
path('index_id02/<int:year>/<int:month>/<int:day>/<int:id>', helloWorld.views.index_id02),
# 正则表达式匹配是必须使用re_path方法,正则表达式"?P"开头是固定格式
re_path('index_id03/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})', helloWorld.views.index_id03),
# 配置媒体文件的路由地址
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 命名空间namespace--比如说是"user/"开头的,第一个参数include(),第二个参数namespace
# 导包引入include模块,include()里面也有两个参数,第一个是指定user的urls,第二个是项目名;
path('user/', include(('user.urls', 'user'), namespace='user')),
path('order/', include(('order.urls', 'order'), namespace='order')),
# 配置 download_file
path('download1/', helloWorld.views.download_file1),
path('download2/', helloWorld.views.download_file2),
path('download3/', helloWorld.views.download_file3),
path('get', helloWorld.views.get_test),
path('post', helloWorld.views.post_test),
path('toLogin/', helloWorld.views.to_login),
path('login', helloWorld.views.login),
path('toUpload/', helloWorld.views.to_upload),
path('upload', helloWorld.views.upload),
path('student/list', helloWorld.views.List.as_view()),
# 默认名称就是"pk",建议不要更改,在开发过程中就默认为pk即可
path('student/<int:pk>', helloWorld.views.Detail.as_view()),
# 如果把默认名称"pk"更改为其他(例如:id),则需要在urls.py配置文件Detail类中添加pk_url_kwarg参数
# path('student/<int:id>', helloWorld.views.Detail.as_view())
path('student/create', helloWorld.views.Create.as_view()),
path('student/update/<int:pk>', helloWorld.views.Update.as_view()),
path('student/delete/<int:pk>', helloWorld.views.Delete.as_view()),
path('toCourse/', helloWorld.views.to_course),
path('book/list', helloWorld.views.bookList),
path('book/list2', helloWorld.views.bookList2),
path('book/preAdd', helloWorld.views.preAdd),
path('book/add', helloWorld.views.add),
path('book/preUpdate/<int:id>', helloWorld.views.preUpdate),
path('book/delete/<int:id>', helloWorld.views.delete),
path('book/update', helloWorld.views.update),
path('transfer/', helloWorld.views.transfer),
path('book/preAdd2', helloWorld.views.preAdd2),
path('book/preAdd3', helloWorld.views.preAdd3),
# 跳转注册页面
path('auth/toRegister', helloWorld.views.to_register),
# 提交注册请求
path('auth/register', helloWorld.views.register),
# 跳转登录页面
path('auth/toLogins', helloWorld.views.to_logins),
# 提交登录请求
path('auth/logins', helloWorld.views.logins),
# 修改密码,get请求直接跳转页面,post请求执行处理
path('auth/setPwd', helloWorld.views.setPwd)
]

15、运行项目,浏览器输入"http://127.0.0.1:8000/auth/setPwd"打开修改密码页面,进行修改密码操作,原用户名(dev01)密码(123)烦请自行测试验证,例如:先输入错误的密码,单击提交后报错提示原密码错误,输入准确的原密码来修改,新密码(1234)自定义即可,校验成功,跳转到设置的网站首页,与此同时系统用户表的密码也会被修改,亦是加密后的密码,测试验证能够修改成功。


用户注销实现
用户注销通过auth.logout方法实现,用户登录后进入主页,显示注销功能;如果用户没登录,则显示登录功能;
16、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容,定义实现 Logout(注销) 和 to_index(跳转网站首页) 两个方法;
# 导包
import datetime
import os
from django.contrib import auth
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db import connection, transaction
from django.db.backends.utils import CursorDebugWrapper
from django.db.models import Q, Sum, Avg, F
from django.http import HttpResponse, HttpResponseNotFound, JsonResponse, StreamingHttpResponse, FileResponse
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from helloWorld.forms import StudentForm, BookInfoForm, BookInfoModelForm
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo, AccountInfo
# Create your views here.
# 定义类
class Person:
# 属性 姓名
name = None
# 属性 年龄
age = None
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义一个index方法,里面要加上request请求对象
def index(request):
# 传递字符串类型数据,定义字符串类型变量str
str = 'hello world!'
# 日期对象date,导包引入import datetime
date = datetime.datetime.now()
# 定义字典类型数据
myDict = {"Jack":"11", "Queen":"12", "King":"13"}
# 创建一个对象,例如:zhangsan
zhangsan = Person("张三", 18)
# 定义列表myList、元组myTuple--列表和元组里面的元素类型没有限制,列表里面可以嵌套列表,元组里面可以嵌套元组
myList = [1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10}]
myTuple = (1, 'apple', 3.1415926, True, [5, 6], (7, 8), {9, 10})
# 变量content_value是字典格式
content_value = {"content_msg": str, "msg2": myDict, "msg3": zhangsan, "msg4": myList, "msg5": myTuple, "date": date}
# context= 传递的本身要求格式是一个字典类型
return render(request, 'index.html', context=content_value)
# 定义index_id方法,里面第一个参数request请求对象,第二个参数 id
def index_id(request, id):
# 判断 id是否为0
if id == 0:
# 导包引入redirect模块,如果id等于0的话,重定向到一个目标静态地址
return redirect("/static/error.html")
else:
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse("id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,里面继续跟多个路由变量"year, month, day, id"
def index_id02(request, year, month, day, id):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + "/" + str(month) + "/" + str(day) + "/" +"id是" + str(id) + "的某某平台系统页面")
# 定义index_id方法,第一个参数request请求对象,后面跟多个路由变量"year, month, day"--注意,使用正则后不能与"id"再混合使用了
def index_id03(request, year, month, day):
# 使用HttpResponse直接返回内容--因为id是int类型,里面得使用str()进行转换
return HttpResponse(str(year) + '/' + str(month) + '/' + str(day) + "使用正则路由后的某某平台系统页面")
# 定义目标文件路径
file_path = "D:\\works\\djangoProject\\datas\\IDM.rar"
# 定义download_file1下载方法,请求需要带上request(所有的请求都要带上request)
def download_file1(request):
# 定义文件--使用open函数方法以"rb"二进制读取模式打开文件--然后返回一个file文件对象
file = open(file_path, 'rb')
# 创建构造好了HttpResponse对象之后返回给response
response = HttpResponse(file)
# 指定文件类型
response['Content-Type'] = 'application/rar-compressed'
# 扩展--指定附件及文件名字(可以动态拼接filename,并不建议使用原始名称)
response['Content-Disposition'] = 'attachment; filename=file1.rar'
return response
def download_file2(request):
file = open(file_path, 'rb')
# 创建构造好了StreamingHttpResponse对象之后返回给response
response = StreamingHttpResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file2.rar'
return response
def download_file3(request):
file = open(file_path, 'rb')
# 创建构造好了FileResponse对象之后返回给response
response = FileResponse(file)
response['Content-Type'] = 'application/rar-compressed'
response['Content-Disposition'] = 'attachment; filename=file3.rar'
return response
def get_test(request):
"""
get 请求测试
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'打印常用属性request.content_type:{request.content_type}')
print(f'打印常用属性request.content_params:{request.content_params}')
print(f'打印常用属性request.COOKIES:{request.COOKIES}')
print(f'打印常用属性request.scheme:{request.scheme}')
print(f'打印常用方法request.is_secure:{request.is_secure()}')
print(f'打印常用方法request.get_host:{request.get_host()}')
print(f'打印常用方法request.get_full_path:{request.get_full_path()}')
print(f'使用request.GET.get("name")方法获取对应key值参数:{request.GET.get("name")}' )
print(f'使用request.GET.get("pwd")方法获取对应key值参数:{request.GET.get("pwd")}')
print(f'使用request.GET.get("dev")方法获取不存在的参数,返回值是'None':{request.GET.get("dev")}')
print(f'request.GET.get("prod", "555")获取的prod参数是不存在的,设置返回值'555':{request.GET.get("prod", "555")}')
return HttpResponse("hello world!http get ok!")
def post_test(request):
"""
post 请求测试方法
:param request:
:return:
"""
print(f'打印请求方式request.method:{request.method}')
print(f'使用request.POST.get("name")方法获取对应key值参数:{request.POST.get("name")}')
print(f'使用request.POST.get("pwd")方法获取对应key值参数:{request.POST.get("pwd")}')
print(f'使用request.POST.get("dev")方法获取不存在的参数,返回值是'None':{request.POST.get("dev")}')
print(f'request.POST.get("prod", "556")获取的prod参数是不存在的,设置返回值'556':{request.POST.get("prod", "556")}')
return HttpResponse("hello world!http post ok!")
def to_login(request):
"""
跳转到登录页面
:param request:
:return:
"""
# 跳转到登录页面可直接使用渲染render()方法
return render(request, 'login.html')
def login(request):
"""
登录到主页面
:param request:
:return:
"""
# 首先获取用户名和密码
user_name = request.POST.get('user_name')
pwd = request.POST.get('pwd')
# 模拟用户登录(暂不连接数据库)
if user_name == "python3" and pwd == "123456":
# session中存一个用户名
request.session['currentUserName'] = user_name
print(f'代码脚本中session获取:{request.session['currentUserName']}')
# 获取HttpResponse
response = render(request, 'main.html')
# 通过response.set_Cookie()方法来设置cookie
response.set_cookie('remember_me', True)
return response
else:
# 定义变量content_value为报错提示信息,里面是键值对格式的对象
content_value = {"error_info":"用户名或者密码错误!"}
return render(request, 'login.html', context=content_value)
def to_upload(request):
"""
跳转到上传文件页面
:param request:
:return:
"""
return render(request, 'upload.html')
def upload(request):
"""
上传文件处理
:param request:
:return:
"""
# 获取上传的文件,如果没有文件,就默认为None(如果不写指定的None,也是默认None)
myFile = request.FILES.get("myfile", None)
# 判断如果是有myFile的情况,就是说明有文件
if myFile:
# 打开特定的文件进行二进制的写操作--上传文件路径烦请自行创建(例如:在项目datas路径下新建"myFile"目录文件)
f = open(os.path.join("D:\\works\\djangoProject\\datas\\myFile", myFile.name), "wb+")
# 分块写入文件
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("文件上传成功!")
else:
return HttpResponse("没有发现可以上传的文件!")
# 定义List类,继续继承ListView(导包引入 from django.views.generic import ListView)
class List(ListView):
# 设置模版文件
template_name = 'student/list.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息列表'}
# 定义数据集(查询结果集)--StudentInfo(导入 from helloWorld.models import StudentInfo)
queryset = StudentInfo.objects.all()
# 每页展示数据的条数(自行设置)
paginate_by = 5
# 设置上下文对象名称(其实就是一个列表的对象),建议使用自定义名称,不然就默认为 objectlist
context_object_name = 'student_list'
# 定义Detail类,继续继承DetailView(导包引入 from django.views.generic import DetailView)
class Detail(DetailView):
# 设置模版文件
template_name = 'student/detail.html'
# 设置模型外的数据--例如:指定标题
extra_context = {'title': '学生信息详情'}
# 设置查询模型--指定model(不然无法查询数据)
model = StudentInfo
# 设置上下文对象名称
context_object_name = 'student'
# 指定URL中用于获取对象的唯一标识符的参数名称,默认为'pk';
# 如若在urls.py文件中自定义了名称,则需要添加对应pk_url_kwarg参数为自定义名称
# pk_url_kwarg = 'id'
# 定义Create类,继续继承CreateView(导包引入 from django.views.generic import CreateView)
class Create(CreateView):
# 设置模版文件,名称修改为create(有的名称叫"add"也行)
template_name = 'student/create.html'
# 设置模型外的数据--例如:指定标题"添加"或者"新增"都行
extra_context = {'title': '学生信息新增'}
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Update类,继续继承UpdateView(导包引入 from django.views.generic import UpdateView)
class Update(UpdateView):
# 设置模版文件,名称修改为update(自定义)
template_name = 'student/update.html'
# 设置模型外的数据--例如:指定标题"编辑"或者"修改"都行
extra_context = {'title': '学生信息编辑'}
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 因为是表单,所以需要使用form_class参数来指定form表单
form_class = StudentForm
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 定义Delete类,继续继承DeleteView(导包引入 from django.views.generic import DeleteView)
class Delete(DeleteView):
# 设置模版文件,名称修改为delete(自定义)
template_name = 'student/delete.html'
# 设置模型外的数据--例如:指定标题"删除"或者"修改"都行
extra_context = {'title': '学生信息删除'}
# 设置上下文对象名称
context_object_name = 'student'
# 设置查询模型--指定model(不然无法查询数据)--传来一个组件"pk"会自动的去查数据、封装对象、显示到页面上
model = StudentInfo
# 执行成功后跳转地址(跳转地址可以是一个新的页面,也可以进入一个列表页面)
success_url = '/student/list'
# 自定义跳转子类模板页面方法
def to_course(request):
"""
跳转到子类模板页面
:param request:
:return:
"""
return render(request, 'course.html')
# 定义bookList方法
def bookList(request):
"""
图书列表查询
"""
# 查询显示所有数据
bookList = BookInfo.objects.all()
# 使用BookInfo.objects.extra()方法,里面使用where加参数(元组格式),在params加上具体的参数,也是一个元组
# 如果是模型外的参数(models.py里面没有定义的参数),可以使用BookInfo.objects.select()方法
# bookList = BookInfo.objects.extra(where=["price>%s"], params=[90])
# # 使用BookInfo.objects.raw()方法,直接写一个SQL语句
# bookList = BookInfo.objects.raw('SELECT * FROM t_book where price>%s', params=[90])
# 使用connection方法需要导包引入from django.db import connection模块,返回一个cursor游标
# 指定cursor游标为CursorDebugWrapper类型,需导包引入from django.db.backends.utils import CursorDebugWrapper模块
cursor: CursorDebugWrapper = connection.cursor()
# 然后就可以执行使用execute方法,查询图书价格大于90的记录数
# cursor.execute('select count(*) from t_book where price>90')
# print('预计提取的一个结果是(2,):', cursor.fetchone())
content_value = {"title": "图书列表", "bookList": bookList}
return render(request, 'book/list.html', context=content_value)
def bookList2(request):
"""
多表查询,有正向查询和反向查询
:param request:
:return:
"""
# 正向查询(经常使用)--多的一端BookInfo条件id=2且只查询一条数据,返回图书book并指定类型BookInfo
book: BookInfo = BookInfo.objects.filter(id=2).first()
# 能够输出book的所有信息,也能输出所关联的bookType.bookTypeName数据信息
print(book.bookName, book.bookType.bookTypeName)
# 反向查询(很少使用)--(导包引入from helloWorld.models import BookTypeInfo)
# 一的一端BookTypeInfo条件id=1且只查询一条数据,返回图书类别bookType并指定类型BookTypeInfo
bookType: BookTypeInfo = BookTypeInfo.objects.filter(id=1).first()
# 输出读取关联的这个图书类别下的所有图书的数据集中第一条数据,固定语法bookinfo_set
print(bookType.bookinfo_set.first().bookName)
# 显示这个类别下的所有数据,返回的结果是一个QuerySet数据集,这个类型下有两条数据,
print(bookType.bookinfo_set.all())
# 把QuerySet这个数据集转发到页面上就可以进行遍历了
content_value = {"title": "图书列表", "bookList": bookType.bookinfo_set.all()}
return render(request, 'book/list.html', context=content_value)
def preAdd(request):
"""
预处理,添加操作
:param request:
:return:
"""
# 预处理操作需要先找到所有数据
bookTypeList = BookTypeInfo.objects.all()
print(f'可自行打印查看bookTypeList是否查询出所有数据:{bookTypeList}')
# 预处理操作之后要返回到图书添加页面
content_value = {"title": "图书添加", "bookTypeList": bookTypeList}
return render(request, 'book/add.html', context=content_value)
def preAdd2(request):
"""
预处理,添加操作 使用form表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoForm
form = BookInfoForm()
context_value = {"title": "图书添加2", "form": form}
return render(request, 'book/add2.html', context_value)
def preAdd3(request):
"""
预处理,添加操作 使用ModelForm表单
:param request:
:return:
"""
# 导包引入from helloWorld.forms import BookInfoModelForm
form = BookInfoModelForm()
context_value = {"title": "图书添加3", "form": form}
return render(request, 'book/add3.html', context_value)
def add(request):
"""
图书添加
:param request:
:return:
"""
# 封装对象
book = BookInfo()
# 添加数据
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType")
book.price = request.POST.get("price")
# 因为是模板,所以直接使用save()方法
book.save()
# 数据添加完成之后,可以获取新增数据的主键id
print(f'数据添加完成之后,获取新增数据的主键id:{book.id}')
# 添加完成之后,需要返回到列表,直接return返回那个对象
return bookList(request)
# 修改预处理,定义修改操作方法;页面需要传一个id来确定是要修改哪一条记录
def preUpdate(request, id):
"""
预处理,修改操作
:param request:
:return:
"""
print("通过path里面的变量,页面需要传一个id来确定是要修改哪一条记录:", id)
# 根据传过来的id去查询数据,并返回一个book对象
book = BookInfo.objects.get(id=id)
print(f'可自行打印查看返回的book对象:{book}')
bookTypeList = BookTypeInfo.objects.all()
print(bookTypeList)
# book对象也需要传到页面上去,到时候页面上就能够取值了
content_value = {"title": "图书修改", "bookTypeList": bookTypeList, "book": book}
return render(request, 'book/edit.html', context=content_value)
def update(request):
"""
图书修改
:param request:
:return:
"""
book = BookInfo()
book.id = request.POST.get("id")
book.bookName = request.POST.get("bookName")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType_id")
book.price = request.POST.get("price")
book.save()
return bookList(request)
def delete(request, id):
"""
图书删除
:param request:
:return:
"""
# 删除指定id数据
BookInfo.objects.get(id=id).delete()
# 根据条件删除多条数据
# BookInfo.objects.filter(price__gte=100).delete()
# 删除所有数据
# BookInfo.objects.all().delete()
return bookList(request)
# 定义转账transfer方法--导包引入from django.db import transaction模块使用事务
@transaction.atomic
def transfer(request):
"""
模拟转账
:param request:
:return:
"""
# 开启事务,
sid = transaction.savepoint()
# 添加异常处理机制
try:
# 导包引入from helloWorld.models import AccountInfo方法
# AccountInfo.objects.filter()方法查找A用户
a1 = AccountInfo.objects.filter(user='A用户_赵大')
# 导包引入from django.db.models import F 模块
a1.update(account = F('account') + 100)
# 这个"'A用户_赵大'"账户是加account余额,那么对应的"'B 用户_ 钱二'"账户就是减account余额
b2 = AccountInfo.objects.filter(user='B用户_钱二')
# 修改操作
b2.update(account = F('account') - 100 / 0)
# 提交事务,如果不设置,当程序执行完成后,会自动提交事务
transaction.savepoint_commit(sid)
except Exception as e:
print(f'异常信息为:{e}')
# 事务回滚--传一个sid表示需要事务回滚哪一个事务
transaction.savepoint_rollback(sid)
# 执行完两个操作之后,模拟转账完成,返回到界面
return HttpResponse("OK!转账完成!")
def to_register(request):
"""
跳转注册页面
:param request:
:return:
"""
return render(request, 'auth/register.html')
def register(request):
"""
用户注册
:param request:
:return:
"""
# 首先需要获取用户名密码参数
username = request.POST.get('username')
password = request.POST.get('password')
# 检验用户名是否存在
result = User.objects.filter(username=username)
if result:
return render(request, 'auth/register.html',
context={"errorInfo": "该用户名已存在", "username": username, "password": password})
# 导包引入from django.contrib.auth.models import User模型,使用封装好的create_user方法操作数据库
User.objects.create_user(username=username, password=password)
return render(request, "auth/login.html")
def to_logins(request):
"""
跳转登录页面
:param request:
:return:
"""
return render(request, 'auth/login.html')
def logins(request):
"""
登录处理
:param request:
:return:
"""
username = request.POST.get('username')
password = request.POST.get('password')
# 导包引入from django.contrib import auth模块,通过auth模块authenticate验证方法来验证,验证方法里面要传入用户名和密码
# authenticate验证方法的第一个参数要的是request,然后是username、password
# 如果验证成功了,校验成功返回用户对象,如果不存在则返回None;指定一个类型去接收返回的用户对象
resUser: User = auth.authenticate(request, username=username, password=password)
print(f'打印查看resUser:{resUser},查看resUser类型:{type(resUser)}')
# 如果存在resUser这个用户 并且使用is_active方法判断用户对象在数据库中是否激活
if resUser and resUser.is_active:
# 用户登录成功之后(返回给客户端登录的凭证或者说是令牌、随机字符串)
auth.login(request, resUser)
return render(request, 'auth/index.html')
else:
return render(request, 'auth/login.html',
context={"errorInfo": "用户名或者密码错误", "username": username, "password": password})
def setPwd(request):
"""
修改密码
:param request:
:return:
"""
if request.method == "POST":
oldPwd = request.POST.get("oldPwd")
newPwd = request.POST.get("newPwd")
# 1、校验用户密码(原密码) check_password
isRight = request.user.check_password(oldPwd)
if not isRight:
return render(request, 'auth/setPwd.html',
context={"errorInfo": "原密码错误!", "oldPwd": oldPwd, "newPwd": newPwd})
# 2、设置新密码 set_password 里面实现了加密
request.user.set_password(newPwd)
# 3、保存用户信息
request.user.save()
return render(request, 'auth/index.html')
return render(request, "auth/setPwd.html")
def logout(request):
"""
用户注销
:param request:
:return:
"""
# auth.logout()注销,里面要带上request参数
auth.logout(request)
# 注销完成之后跳转到主页(设置的网站首页)
return render(request, 'auth/index.html')
def to_index(request):
"""
跳转主页,直接返回主页
:param request:
:return:
"""
return render(request, 'auth/index.html')

17、修改"djangoProject"项目"templates"目录"auth"目录文件路径下的"index.html"文件内容,通过is_authenticated()方法可以判断用户是否登录认证,输入以下内容;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>网站首页</title>
</head>
<body>
设置的网站首页;
{# 在模板中添加判断,通过is_authenticated()方法可以判断用户是否登录认证 #}
{% if request.user.is_authenticated %}
网站主页,欢迎: {{ request.user }}<br/>
<a href="/auth/logout">注销</a>
{% else %}
<a href="/auth/toLogins">登录</a>
{% endif %}
</body>
</html>

18、修改"djangoProject"应用下的"urls.py"配置文件内容,配置定义映射关系;
"""
URL configuration for djangoProject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.contrib import admin
from django.urls import path, re_path, include
from django.views.generic import RedirectView
from django.views.static import serve
import helloWorld.views
urlpatterns = [
path('admin/', admin.site.urls),
# 可直接复制上面"admin",把"admin"修改为"index";后面是跟的"处理函数helloWorld.views.index"
# 是helloWorld应用的views里面的index()--引入helloWorld.views,记得index后不能加小括号,因为传入的是对象;
path('index/', helloWorld.views.index, name='index'),
# 要是请求"redirectTo"这个请求的话给重定向到"index"--重定向使用RedirectView.as_view(),里面使用关键词参数url
path('redirectTo', RedirectView.as_view(url="index/")),
# 自定义名称,例如叫"index_id/",后面再跟上某网页id;<int:id> int指定类型,路由变量为id;对应对应的路由映射
path('index_id/<int:id>', helloWorld.views.index_id),
# 多个路由变量
path('index_id02/<int:year>/<int:month>/<int:day>/<int:id>', helloWorld.views.index_id02),
# 正则表达式匹配是必须使用re_path方法,正则表达式"?P"开头是固定格式
re_path('index_id03/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})', helloWorld.views.index_id03),
# 配置媒体文件的路由地址
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 命名空间namespace--比如说是"user/"开头的,第一个参数include(),第二个参数namespace
# 导包引入include模块,include()里面也有两个参数,第一个是指定user的urls,第二个是项目名;
path('user/', include(('user.urls', 'user'), namespace='user')),
path('order/', include(('order.urls', 'order'), namespace='order')),
# 配置 download_file
path('download1/', helloWorld.views.download_file1),
path('download2/', helloWorld.views.download_file2),
path('download3/', helloWorld.views.download_file3),
path('get', helloWorld.views.get_test),
path('post', helloWorld.views.post_test),
path('toLogin/', helloWorld.views.to_login),
path('login', helloWorld.views.login),
path('toUpload/', helloWorld.views.to_upload),
path('upload', helloWorld.views.upload),
path('student/list', helloWorld.views.List.as_view()),
# 默认名称就是"pk",建议不要更改,在开发过程中就默认为pk即可
path('student/<int:pk>', helloWorld.views.Detail.as_view()),
# 如果把默认名称"pk"更改为其他(例如:id),则需要在urls.py配置文件Detail类中添加pk_url_kwarg参数
# path('student/<int:id>', helloWorld.views.Detail.as_view())
path('student/create', helloWorld.views.Create.as_view()),
path('student/update/<int:pk>', helloWorld.views.Update.as_view()),
path('student/delete/<int:pk>', helloWorld.views.Delete.as_view()),
path('toCourse/', helloWorld.views.to_course),
path('book/list', helloWorld.views.bookList),
path('book/list2', helloWorld.views.bookList2),
path('book/preAdd', helloWorld.views.preAdd),
path('book/add', helloWorld.views.add),
path('book/preUpdate/<int:id>', helloWorld.views.preUpdate),
path('book/delete/<int:id>', helloWorld.views.delete),
path('book/update', helloWorld.views.update),
path('transfer/', helloWorld.views.transfer),
path('book/preAdd2', helloWorld.views.preAdd2),
path('book/preAdd3', helloWorld.views.preAdd3),
# 跳转注册页面
path('auth/toRegister', helloWorld.views.to_register),
# 提交注册请求
path('auth/register', helloWorld.views.register),
# 跳转登录页面
path('auth/toLogins', helloWorld.views.to_logins),
# 提交登录请求
path('auth/logins', helloWorld.views.logins),
# 修改密码,get请求直接跳转页面,post请求执行处理
path('auth/setPwd', helloWorld.views.setPwd),
# 用户注销
path('auth/logout', helloWorld.views.logout),
# 跳转主页,直接返回主页(设置的网站首页)
path('auth/index', helloWorld.views.to_index)
]

19、运行项目,浏览器输入"http://127.0.0.1:8000/auth/index"自行测试验证。

Django5 内置其他高级功能
Diango5为开发者提供了常见的Web应用支持,例如:会话控制(session)、缓存机制(还没有讲,比如:使用 redis 或者文件缓存等)、CSRE防护(表单中有介绍)、消息框架、分页功能、国际化和本地化(settings.py 配置文件设置)、和自定义中间件等,有效的提高了开发者的开发效率;
一些其他更高级的功能主要是在项目实战中介绍,基础知识中不是很好举例说明,这些 Diango 基础知识点基本上都有涉及,部分没涉及的,比如"缓存机制",一般是使用redis,后面实战项目中详细介绍。
未完待续......