来源引用网络知识与某站曹老师视频相互结合学习记录,仅供参考!
Django 模型定义和使用
Django5 对各种数据库提供了很好的支持,包括PostgreSQL、MySQL、SQLite和 Oracle,而且为这些数据库提供了统一的API方法,这些API统称为ORM 框架;就是通过一套接口实现不同的定义,然后使用同一套接口去操作不同的数据库,这个就是 ORM 框架;通过使用Django5内置的ORM框架可以实现数据库连接和读写操作(主要实现数据库连接和读写操作),也包括一些数据库事务。
四、Django 模型数据新增
Django对数据库的数据进行增、删、改操作都是借助内置ORM框架所提供的API方法实现的,简单来说,它在模型基础类 Model 里定义数据操作方法,通过类继承将这些操作方法传给开发者自定义的模型对象,再由模型对象调用即可实现数据操作;添加操作通过模型的save方法实现,添加下可以返回主键id值(这个 API 的话就是模型里面有个 save 方法就能实现新增、而且添加之后可以返回主键 id 值);
实例说明
因为在"http://127.0.0.1:8000/book/list"或者"http://127.0.0.1:8000/book/list2"图书列表页面里面添加页面是需要图书类别的数据,是不太可能使用外键"bookType_id"的,大部分情况下对于业务数据都是采用来下拉框实现的,让它通过下拉选择框来选择图书类别,所以需要添加一个预处理操作;
1、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容 bookList 方法查询显示所有图书列表数据,再新增预处理操作,定义一个添加预处理 preAdd 方法;
# 导包
import datetime
import os
from django.core.paginator import Paginator
from django.db.models import Q, Sum, Avg
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
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo
# 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()
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)

2、修改项目"templates"目录"book"目录文件路径下的"list.html"的文件内容,新增一个"图书添加"的跳转,跳转到"添加"页面(此时还没有创建添加页面);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<a href="/book/preAdd">图书添加</a><br/><br/>
<table border="1">
<tr>
<th>编号</th>
<th>图书名称</th>
<th>图书价格</th>
<th>出版日期</th>
<th>图书类别</th>
</tr>
{% for book in bookList %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.bookName }}</td>
<td>{{ book.price }}</td>
<td>{{ book.publishDate | date:'Y-m-d' }}</td>
<td>{{ book.bookType.bookTypeName }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>


3、 在项目"templates"目录"book"的目录文件下新建一个名称为"add"的HTML 文件,输入以下内容(此时单击"图书添加"即可成功跳转打开图书添加页面);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<form action="/book/add" method="post">
{% csrf_token %}
<table>
<tr>
<td>图书名称:</td>
<td>
<input type="text" name="bookName">
</td>
</tr>
<tr>
<td>出版日期:</td>
<td>
<input type="text" name="publishDate">
</td>
</tr>
<tr>
<td>图书类别:</td>
<td>
<select name="bookType_id">
{% for bookType in bookTypeList %}
<option value="{{ bookType.id }}">{{ bookType.bookTypeName }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>图书价格:</td>
<td>
<input type="text" name="price">
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
</body>
</html>


4、修改"helloWorld"应用下的"views.py"配置文件内容,新增添加函数 add 方法;
# 导包
import datetime
import os
from django.core.paginator import Paginator
from django.db.models import Q, Sum, Avg
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
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo
# 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()
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 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_id")
book.price = request.POST.get("price")
# 因为是模板,所以直接使用save()方法
book.save()
# 数据添加完成之后,可以获取新增数据的主键id
print(f'数据添加完成之后,获取新增数据的主键id:{book.id}')
# 添加完成之后,需要返回到列表,直接return返回那个对象
return bookList(request)

5、修改"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)
]

6、运行项目,浏览器输入"http://127.0.0.1:8000/book/list"或"http://127.0.0.1:8000/book/list2"打开图书列表页面,单击"图书添加"打开图书添加页面,依次输入填写字段信息,然后点击"提交"按钮,经测试验证,能够图书添加成功,图书添加成功后会返回跳转到图书列表页面并显示最新数据信息。

五、Django 模型数据修改
模型数据修改和添加都是用的save方法。
7、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容,先定义一个添加预处理 preUpdate方法,修改预处理操作,根据id获取图书信息,以及获取图书类别列表;
# 导包
import datetime
import os
from django.core.paginator import Paginator
from django.db.models import Q, Sum, Avg
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
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo
# 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()
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 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_id")
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)

8、修改项目"templates"目录"book"目录文件路径下的"list.html"的文件内容,新增一个"图书修改"的跳转操作链接,跳转到"图书修改"页面(此时还没有创建添加页面);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<a href="/book/preAdd">图书添加</a><br/><br/>
<table border="1">
<tr>
<th>编号</th>
<th>图书名称</th>
<th>图书价格</th>
<th>出版日期</th>
<th>图书类别</th>
<th>更多操作</th>
</tr>
{% for book in bookList %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.bookName }}</td>
<td>{{ book.price }}</td>
<td>{{ book.publishDate | date:'Y-m-d' }}</td>
<td>{{ book.bookType.bookTypeName }}</td>
<td>
<a href="/book/preUpdate/{{ book.id }}">图书修改</a>
</td>
</tr>
{% endfor %}
</table>
</body>
</html>

9、 在项目"templates"目录"book"的目录文件下新建一个名称为"edit"的HTML 文件,输入以下内容(此时单击"图书修改"即可成功跳转打开图书添加页面);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<form action="/book/update" method="post">
{% csrf_token %}
<table>
<tr>
<td>图书名称:</td>
<td>
<input type="text" name="bookName" value="{{ book.bookName }}">
</td>
</tr>
<tr>
<td>出版日期:</td>
<td>
<input type="text" name="publishDate" value="{{ book.publishDate | date:'Y-m-d' }}">
</td>
</tr>
<tr>
<td>图书类别:</td>
<td>
<select name="bookType_id">
{% for bookType in bookTypeList %}
<option value="{{ bookType.id }}"
{% if book.bookType.id == bookType.id %}selected{% endif %}>
{{ bookType.bookTypeName }}
</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>图书价格:</td>
<td>
<input type="text" name="price" value="{{ book.price }}">
</td>
</tr>
<tr>
<td colspan="2">
<input type="hidden" name="id" value="{{ book.id }}">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
</body>
</html>

10、修改"helloWorld"应用下的"views.py"配置文件内容,新增添加函数 update 方法,保存图书信息;
# 导包
import datetime
import os
from django.core.paginator import Paginator
from django.db.models import Q, Sum, Avg
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
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo
# 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()
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 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_id")
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)

11、修改"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/update', helloWorld.views.update)
]

12、运行项目,浏览器输入"http://127.0.0.1:8000/book/list"或"http://127.0.0.1:8000/book/list2"打开图书列表页面,单击列表"更多操作→图书添加"打开图书修改页面,自定义修改,然后点击"提交"按钮,经测试验证,能够图书修改成功,图书修改成功后会返回跳转到图书列表页面并显示最新数据信息。

六、Django 模型数据删除
Django5 ORM 框架提供了 delete()方法来实现数据的删除操作,不过在平时开发过程中有三种常用的方式,一种是删除所有数据,还有一种是经常使用到的"根据指定 id 来删除数据",最后一种是根据filter条件删除多条数据;
# 删除所有数据
BookInfo.objects.all().delete()
# 删除指定id数据
BookInfo.objects.get(id=1).delete()
# 根据条件删除多条数据--__gte高级查询匹配符"大于等于"
BookInfo.objects.filter(price__gte=100).delete()
删除指定 id 数据
13、修改"djangoProject"项目"helloWorld"应用下的"views.py"配置文件内容,定义一个 delete 方法;
# 导包
import datetime
import os
from django.core.paginator import Paginator
from django.db.models import Q, Sum, Avg
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
from helloWorld.models import StudentInfo, BookInfo, BookTypeInfo
# 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()
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 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_id")
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)

14、修改项目"templates"目录"book"目录文件路径下的"list.html"的文件内容,新增一个"图书删除"操作;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<a href="/book/preAdd">图书添加</a><br/><br/>
<table border="1">
<tr>
<th>编号</th>
<th>图书名称</th>
<th>图书价格</th>
<th>出版日期</th>
<th>图书类别</th>
<th>更多操作</th>
</tr>
{% for book in bookList %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.bookName }}</td>
<td>{{ book.price }}</td>
<td>{{ book.publishDate | date:'Y-m-d' }}</td>
<td>{{ book.bookType.bookTypeName }}</td>
<td>
<a href="/book/preUpdate/{{ book.id }}">图书修改</a>
<a href="/book/delete/{{ book.id }}">图书删除</a>
</td>
</tr>
{% endfor %}
</table>
</body>
</html>

15、修改"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)
]

16、运行项目,浏览器输入"http://127.0.0.1:8000/book/list"或"http://127.0.0.1:8000/book/list2"打开图书列表页面,单击列表中对应的"图书删除"链接即可删除对应的一条图书信息;"删除所有数据"和"根据条件删除多条数据"可自行测试验证,建议可根据数据库表对照,在进行"删除"操作前可导出一份数据用于备份。
INSERT INTO `t_book` (`id`, `bookName`, `price`, `publishDate`, `bookType_id`) VALUES (1, 'Java编程思想', 100, '2004-03-16', 1);
INSERT INTO `t_book` (`id`, `bookName`, `price`, `publishDate`, `bookType_id`) VALUES (2, 'Head First设计模式', 88, '2020-03-16', 1);
INSERT INTO `t_book` (`id`, `bookName`, `price`, `publishDate`, `bookType_id`) VALUES (3, '数学的秘密', 50, '2019-03-06', 2);
INSERT INTO `t_book` (`id`, `bookName`, `price`, `publishDate`, `bookType_id`) VALUES (4, '语言艺术', 90, '2021-05-20', 3);
INSERT INTO `t_book` (`id`, `bookName`, `price`, `publishDate`, `bookType_id`) VALUES (5, '英语2', 97.8, '2000-12-12', 1);

未完待续......