15.Ajax请求
浏览器向网站发送请求时:
- GET
- POST
特点:页面会刷新。
也可以基于Ajax向后台发送请求(偷偷发送请求)
-
依赖jQuery
-
编写ajax
$.ajax({ url:"发送的地址", type:"post", data:{ n1:123, n2:456, } success:function(res){ console.log(res) } })
15.1GET请求
<script type="text/javascript">
function clickMe() {
$.ajax({
url:'/task/ajax/',
type:"get",
data:{
n1:123,
n2:456,
},
success:function (res) {
console.log(res);
}
})
}
</script>
def task_ajax(request):
print(request.GET)
return HttpResponse("成功了")
15.2POST请求
<script type="text/javascript">
function clickMe() {
$.ajax({
url:'/task/ajax/',
type:"post",
data:{
n1:123,
n2:456,
},
success:function (res) {
console.log(res);
}
})
}
</script>
@csfr_exempt
def task_ajax(request):
print(request.POST)
return HttpResponse("成功了")
15.3使用jQuery绑定事件
{% extends "layout.html" %}
{% block title %}
任务管理
{% endblock %}
{% block css %}
<style>
</style>
{% endblock %}
{% block content %}
<div class="container">
<h1>任务列表</h1>
<h3>示例1</h3>
<input type="button" class="btn btn-primary" value="点击" id="btn1">
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
// 页面框架加载完成之后代码自动执行
bindBtn1Event();
})
//绑定在btn1上的事件
function bindBtn1Event() {
$("#btn1").click(function () {
$.ajax({
url:'/task/ajax/',
type:'post',
data:{
n1:123,
n2:456,
},
success: function (res) {
console.log(res);
}
});
})
}
</script>
{% endblock %}
15.4 ajax请求的返回值
一般不会返回页面,而是一个JSON格式
{% block content %}
<h3>示例1</h3>
<input type="button" class="btn btn-primary" value="点击" id="btn1">
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
// 页面框架加载完成之后代码自动执行
bindBtn1Event();
})
//绑定在btn1上的事件
function bindBtn1Event() {
$("#btn1").click(function () {
$.ajax({
url:'/task/ajax/',
type:'post',
data:{
n1:123,
n2:456,
},
dataType:"JSON",//通过逆序列化将字典变成JSON文件,之后可以通过.key获取值
success: function (res) {
console.log(res.status);
console.log(res.data);
}
});
})
}
</script>
{% endblock %}
# 用装饰器直接跳过csfr_token
@csrf_exempt
def task_ajax(request):
"""Ajax"""
data_dict = {"status": True, "data": [11, 22, 33, 44]}
# 对json格式进行dump生成字典,否则输出为object[JSON]
json_string = json.dumps(data_dict)
# return JsonResponse(data_dict)
return HttpResponse(json_string)
含有input框的请求
<h3>示例2</h3>
<input type="text" id="txtUser" placeholder="姓名">
<input type="number" id="txtAge" placeholder="年龄">
<input type="submit" class="btn btn-primary" value="提交" id="btn2">
<script>
//绑定在btn2上的事件
function bindBtn2Event() {
$("#btn2").click(function () {
$.ajax({
url:'/task/ajax/',
type:'post',
//获取input的值,提交到后台
data:{
n1:$("#txtUser").val(),
n2:$("#txtAge").val(),
},
dataType:"JSON",//通过逆序列化将字典变成JSON文件,之后可以通过.key获取值
success: function (res) {
console.log(res.status);
console.log(res.data);
}
});
})
}
</script>
含有多个input框 - 使用form + name
<h3>示例3</h3>
<form id="form3">
<input type="text" name="user" placeholder="姓名">
<input type="text" name="age" placeholder="年龄">
<input type="text" name="email" placeholder="邮件">
<input type="text" name="more" placeholder="更多">
</form>
<input type="submit" class="btn btn-primary" value="提交" id="btn3">
<script>
//绑定在btn3上的事件
function bindBtn3Event() {
$("#btn3").click(function () {
$.ajax({
url:'/task/ajax/',
type:'post',
//获取input的值,提交到后台
data:$("#form3").serialize(),
dataType:"JSON",//通过逆序列化将字典变成JSON文件,之后可以通过.key获取值
success: function (res) {
console.log(res.status);
console.log(res.data);
}
});
})
}
</script>
15.5通过Ajax添加数据
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">表单</div>
<div class="panel-body">
<form id="formAdd" novalidate>
<div class="col-xs-6">
<div class="clearfix">
<div class="form-group" style="position:relative;">
<label>{{ form.title.label }}</label>
{{ form.title }}
<span class="error_msg" style="color:red;position:absolute;"></span>
</div>
<div class="form-group" style="position:relative;">
<label>{{ form.level.label }}</label>
{{ form.level }}
<span class="error_msg" style="color:red;position:absolute;"></span>
</div>
<div class="form-group" style="position:relative;">
<label>{{ form.user.label }}</label>
{{ form.user }}
<span class="error_msg" style="color:red;position:absolute;"></span>
</div>
<button id="btnAdd" type="button" class="btn btn-primary">提 交</button>
</div>
</div>
<div class="col-xs-6">
<div class="clearfix">
<div class="form-group" style="position:relative;">
<label>{{ form.detail.label }}</label>
{{ form.detail }}
<span class="error_msg" style="color:red;position:absolute;"></span>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
// 页面框架加载完成之后代码自动执行
btnAddEvent()
})
//绑定在btnAdd上的事件
function btnAddEvent() {
$("#btnAdd").click(function () {
$(".error_msg").empty();//先将错误信息置为空
$.ajax({
url:'/task/add/',
type:'post',
data:$("#formAdd").serialize(),
dataType:"JSON",
success:function (res) {
if(res.status){
alert("添加成功")
}else{
$.each(res.error, function (name, data){
console.log(name, data);
$("#id_" + name).next().text(data[0])
})
}
}
})
})
}
</script>
{% endblock %}
views -> task.py
@csrf_exempt
def task_add(request):
"""添加任务"""
print(request.POST)
# <QueryDict: {'title': [''], 'level': ['1'], 'user': [''], 'detail': ['']}>
# 1.用户发送过来的数据进行校验(ModelForm)
form = TaskModelForm(data=request.POST)
if form.is_valid():
form.save()
# 不能使用redirect跳转,因为ajax在发送时候不修改页面, 可以返回一个json给页面,然后页面根据对应的内容进行操作
status_dict = {"status": True}
return HttpResponse(json.dumps(status_dict))
status_dict = {"status": False, "error": form.errors}
return HttpResponse(json.dumps(status_dict, ensure_ascii=False))
utils -> modelform.py
class TaskModelForm(BootStrapModelForm):
class Meta:
model = models.Task
fields = ["title", "level", "user", "detail"]
widgets = {
# "detail":forms.TextInput, text框
# "detail": forms.Textarea, textarea框
}
16.知识点回顾
- 创建Django项目
django-admin startproject xxx
- 创建APP & 注册APP
python manage.py startapp yyy
INSTALLED_APP = {
...
'app01.apps.App01Config'
}
不注册APP则无法创建models.py中的表到数据库中
-
配置静态文件路径 & 模板的路径
-
配置数据库相关的操作
-
第三方模块(django3版本)
pip install mysqlclient
-
先去MySQL中创建一个数据库
-
配置和数据库的连接 settings.py文件
-
在app下的models.py中编写数据库文件(如果使用sqlite3数据库,直接从这一步开始即可)
-
执行makemigrations和migrate
-
-
urls.py -> 路由 URL和函数的对应关系
-
views.py 视图函数 编写业务逻辑
-
templates目录, 编写HTML模板 模板语法、继承、
-
ModelForm & Form组件,在开发增删改查时候
- 生成HTML标签(生成默认值)
- 请求数据进行校验(钩子方法, 正则)
- 保存到数据库(ModelForm)
- 获取错误请信息(ErrorValidation 和 add_errors)
-
Cookie和Session,保存用户的登录信息
-
中间件,基于中间件实现用户认证,基于:
process_request
。 -
ORM操作
mdoels.User.objects.filter(id="xxx")
-
分页组件的应用
订单
-
表结构
class Order(models.Model): """订单""" oid = models.CharField(verbose_name="订单号", max_length=64) title = models.CharField(verbose_name="名称", max_length=32) price = models.IntegerField(verbose_name="价格") status_choices = ( (1, "待支付"), (2, "已支付"), ) status = models.SmallIntegerField( verbose_name="状态", choices=status_choices, default=1 ) admin = models.ForeignKey( verbose_name="管理员", to="Admin", on_delete=models.CASCADE )
想要去数据库中获取数据时:对象/字典
# 对象当前行的所有数据
row_object = models.Order.objects.filter(id=uid).first()
row_object.id
row_object.title
# 取某几列,字典类(因为json)
row_object = models.Order.objects.filter(id=uid).values("id","title").first()
# queryset = [obj, obj, obj]
queryset = models.Order.objects.all()
# queryset = [{"id":xx, "title":yy }, {}, {}]
queryset = models.Order.objects.all().values("id", "title")
#queryset = [(), (), ()]
queryset = models.Order.objects.all().values_list("id"m "title")
views -> order.py
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from django import forms
import random
from datetime import datetime
from app01 import models
from app01.utils.bootstrap_form import BootStrapModelForm
from app01.utils.pagination import Pagination
class OrderModelForm(BootStrapModelForm):
class Meta:
model = models.Order
# fields = "__all__"
# 订单号由系统生成
exclude = ["oid", "admin"]
def order_list(request):
queryset = models.Order.objects.all().order_by("-id")
page_object = Pagination(request, queryset)
form = OrderModelForm()
return render(
request,
"order_list.html",
{
"form": form,
"queryset": page_object.page_queryset,
"page_string": page_object.html(),
},
)
@csrf_exempt
def order_add(request):
"""新建订单(Ajax请求)"""
form = OrderModelForm(data=request.POST)
if form.is_valid():
# 缺少oid
# 生成一个以 年月日时分秒 + 随机生成值 构建的oid
form.instance.oid = datetime.now().strftime("%Y%m%d%H%M%S") + str(
random.randint(1000, 9999)
)
# 管理员 当外键为admin时候,实际上数据库中存储的是admin_id字段 为其添加当前系统的登录的管理员
form.instance.admin_id = request.session["info"]["id"]
form.save()
# 等价于HttpResponse(json.dumps({"status":True}))
return JsonResponse({"status": True})
"""console.log(res)
{
"status": false,
"error": {
"title": ["这个字段是必填项。"],
"price": ["这个字段是必填项。"],
"admin": ["这个字段是必填项。"],
}
}
"""
return JsonResponse({"status": False, "error": form.errors})
def order_delete(request):
"""删除订单"""
uid = request.GET.get("uid")
exsits = models.Order.objects.filter(id=uid).exists()
if exsits:
models.Order.objects.filter(id=uid).delete()
return JsonResponse({"status": True})
return JsonResponse({"status": False, "error": "数据不存在,删除失败"})
def order_detail(request):
"""根据ID获取订单详细"""
uid = request.GET.get("uid")
row_dict = (
models.Order.objects.filter(id=uid).values("title", "price", "status").first()
)
if not row_dict:
return JsonResponse({"status": False, "error": "数据不存在,删除失败"})
"""方式一 字典
result = {
"status": True,
"data": {
"title": row_object.title,
"price": row_object.price,
"status": row_object.status,
},
}
"""
return JsonResponse({"status": True, "data": row_dict})
# 从数据库中获取一个对象 row_object
@csrf_exempt
def order_edit(request):
"""编辑页面"""
uid = request.GET.get("uid")
row_object = models.Order.objects.filter(id=uid).first()
if not row_object:
# 编辑的内容不存在(编辑时已被删除)
return JsonResponse({"status": False, "tips": "数据不存在,请重试"})
form = OrderModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return JsonResponse({"status": True})
# 编辑的内容不符合规定
return JsonResponse({"status": False, "error": form.errors})
templates ->order_list.py
{% extends "layout.html" %}
{% block title %}
订单管理
{% endblock %}
{% block css %}
<style>
.unoccupied{
background-color: red;
color: #FFFFFF;
}
</style>
{% endblock %}
{% block 订单管理 %}class="active"{% endblock %}
{% block content %}
<div class="container">
<input type="button" value="新建订单1" class="btn btn-success" id="btnAdd">
<input type="button" value="新建订单2" class="btn btn-success" data-toggle="modal" data-target="#myModal">
<div class="panel panel-default" style="height:460px;margin-top:20px;">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-list-ul"></i> 订单列表</h3>
</div>
<table class="table table-hover table-bordered" style="padding:0 20px 0 20px;">
<thead>
<tr>
<th>ID</th>
<th>订单号</th>
<th>名称</th>
<th>价格</th>
<th>状态</th>
<th>管理员</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for item in queryset %}
<tr uid="{{ item.id }}">
<td>{{ item.id }}</td>
<td>{{ item.oid}}</td>
<td>{{ item.title}}</td>
<td>{{ item.price }}</td>
<td
{% if item.status == 1 %}
class="unoccupied"
{% endif %}
>{{ item.get_status_display }}</td>
<td>{{ item.admin.username }}</td>
<td>
<input uid={{ item.id }} type="button" class="btn btn-primary btn-xs btn-edit" value="编辑">
<span> </span>
<input uid={{ item.id }} type="button" class="btn btn-danger btn-xs btn-delete" value="删除">
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div><!--panel-->
<ul class="pagination">
{{ page_string }}
</ul>
</div>
<!-- 新建/编辑订单对话框 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel"></h4>
</div>
<div class="modal-body">
<form id="formAdd" novalidate>
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<spanv class="error_msg" style="color:red;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="BtnSave">保存</button>
</div>
</div>
</div>
</div>
<!-- 删除订单对话框 -->
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="alert alert-danger alert-dismissible fade in" role="alert">
<h4>确认删除?</h4>
<p style="margin:10px;">删除后所有关联的相关数据都会被删除</p>
<p style="text-align:right;">
<button id="btn-confrim-delete" type="button" class="btn btn-danger">确认</button>
<!-- data-dismiss="modal" 取消对话框 -->
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</p>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
var DELETE_ID ;
var EIDT_ID ;
$(function () {
bindBtnAddEvent();
bindBtnSaveEvent();
bindBtnDeleteEvent();
bindBtnConfirmDeleteEvent();
bindBtnEditEvent();
})
function bindBtnAddEvent() {
$("#btnAdd").click(function () {
//将正在编辑的ID设置为空
EIDT_ID = undefined;
//清空由Edit留下的数据 $()[0]是对应的DOM
$("#formAdd")[0].reset()
//清除所有错误信息
$(".error_msg").empty();
//点击按钮,显示对话框
$("#myModal").modal('show');
//修改对话框标题
$("#myModalLabel").text("新建")
})
}
function bindBtnSaveEvent() {
$("#BtnSave").click(function () {
//清除所有错误信息
$(".error_msg").empty();
//根据EDIT_ID来确认当前保存的是新建数据还是编辑数据
if(EIDT_ID){
//编辑
doEdit();
}else{
//添加
doAdd();
}
});
}
function bindBtnDeleteEvent() {
$(".btn-delete").click(function () {
//显示删除对话框
$("#deleteModal").modal('show');
//获取当前行的id并赋值给全局变量
DELETE_ID = $(this).attr("uid")
})
}
function bindBtnConfirmDeleteEvent() {
$("#btn-confrim-delete").click(function () {
//点击确认删除按钮
$.ajax({
url:"/order/delete/", // => /order/delete/?uid=13
type:"GET",
data:{
uid:DELETE_ID,
},
dataType:"JSON",
success:function (res) {
if(res.status){
//alert("删除成功")
//隐藏删除对话框
$("#deleteModal").modal('hide');
// //删除该行数据 通过js删除
// $("tr[uid="+ DELETE_ID + "]").remove()
//刷新页面
location.reload()
}else{
alert(res.error)
}
}
})
});
}
function bindBtnEditEvent() {
$(".btn-edit").click(function () {
//当前id
var currentId = $(this).attr("uid");
EIDT_ID = currentId;
console.log(EIDT_ID)
//修改对话框标题
$("#myModalLabel").text("编辑");
//发送ajax去后端获取当前行的相关数据
$.ajax({
url:"/order/detail/",
type:"get",
data:{
uid:currentId,
},
dataType:"JSON",
success: function (res) {
if(res.status){
// 点击显示模态对话框
$("#myModal").modal("show");
//console.log(res);
//将数据默认赋值到对话框的标签中
$.each(res.data, function (name, value) {
$("#id_"+name).val(value);
})
}else{
alert(res.error);
}
}
})
});
}
function doAdd(){
$.ajax({
url:"/order/add/",
type:"post",
data:$("#formAdd").serialize(),
dataType:"JSON", //将从页面获取到的数据转化为JSON格式
success:function (res){
if(res.status){
alert("创建成功");
//清空表单 jQuery对象[0] - 找到对应的DOM对象 .reset 使用DOM对象的reset置空功能
$("#formAdd")[0].reset();
//关闭对话框
$("#myModal").modal("hide");
//重新加载页面
location.reload()
}else{
//console.log(res.error)
//将错误信息显示在对话框中
$.each(res.error, function (name, errorList) {
//拼接id id_title
$("#id_" + name).next().text(errorList[0]);
})
}
}
})
}
function doEdit(){
$.ajax({
url:"/order/edit/?uid="+EIDT_ID,
type:"post",
data:$("#formAdd").serialize(),
dataType:"JSON", //将从页面获取到的数据转化为JSON格式
success:function (res){
if(res.status){
alert("创建成功");
//清空表单 jQuery对象[0] - 找到对应的DOM对象 .reset 使用DOM对象的reset置空功能 等价于.val("")置空
$("#formAdd")[0].reset();
//关闭对话框
$("#myModal").modal("hide");
//重新加载页面
location.reload()
}else{
//编辑的数据不存在
if(res.tips){
alert(res.tips)
}else{
}
//console.log(res.error)
//将错误信息显示在对话框中
$.each(res.error, function (name, errorList) {
//拼接id id_title
$("#id_" + name).next().text(errorList[0]);
})
}
}
})
}
</script>
{% endblock %}
17.其他知识点
1.图表
- highchart
- echarts(推荐)
柱状图
views -> chart.py
def chart_bar(request):
"""构造柱状图数据"""
# 数据可以去数据库中获取
legend = ["销量", "业绩"]
series_list = [
{"name": "销量", "type": "bar", "data": [5, 20, 36, 10, 10, 20]},
{"name": "业绩", "type": "bar", "data": [6, 24, 44, 50, 10, 60]},
]
x_axis = ["1月", "2月", "3月", "4月", "5月", "6月"]
result = {
"status": True,
"data": {
"legend": legend,
"series_list": series_list,
"x_axis": x_axis,
},
}
return JsonResponse(result)
templates -> chart_list.html
<div class="col-sm-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">饼状图</h3>
</div>
<div class="panel-body">
<div id="m3" style="width:100%;height:400px;"></div>
</div>
</div><!--panel-->
</div>
...
<script src="{% static 'js/echarts.js' %}"></script>
<script type="text/javascript">
$(function () {
InitBar();
})
/*初始化柱状图*/
function InitBar() {
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('m2'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例',
textAlign:"auto",
left:"center",
},
tooltip: {},
legend: { //后台获取
bottom:0,
},
xAxis: {
data: [] //后台获取
},
yAxis: {},
series: [] //后台获取
};
$.ajax({
url:"/chart/bar/",
type:"get",
dataType:"JSON",
success:function(res){
//将后台返回的数据更新到option中
if(res.status){
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_axis;
option.series = res.data.series_list;
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}//res.status
},//success:function(res)
})//$.ajax
}//function InitBar()
</script>
2.关于文件的上传
2.1基本操作
<div class="container">
<form method="post" enctype="multipart/form-data"><!--表单中一定要有enctype属性,否则不会上传文件-->
{% csrf_token %}
<input type="text" name="username">
<input type="file" name="avatar">
<input type="submit" value="提交">
</form>
</div>
def upload_list(request):
"""上传文件"""
if request.method == "GET":
return render(request, "upload_list.html")
# <QueryDict: {'username': ['朱一凡'], 'avatar': ['推荐-划分区域.png']}> 仅上传了文件的字符名而非文件
# print(request.POST) # 请求体中的数据(不包含文件)
# print(request.FILES) # 请求体中的文件
file_object = request.FILES.get("avatar") # 文件对象
print(file_object.name) # 文件名 推荐-划分区域.png
# 将上传的文件写入一张图片中
# 将图片分块上传,然后分块写入到a1.png中,也可以将文件名设置为file_object.name
f = open("a1.png", mode="wb")
for chunk in file_object:
f.write(chunk)
f.close
return HttpResponse("提交成功")
案例:批量上传数据
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-list-ul"></i> 批量上传</h3>
</div>
<div class="panel-body">
<form action="/depart/multi/" enctype="multipart/form-data" method="post">
{% csrf_token %}
<div class="form-group">
<input type="file" name="exc">
</div>
<button type="submit" class="btn btn-info btn-sm">上传</button>
</form>
</div>
def depart_multi(request):
"""批量上传(Excel文件)"""
from openpyxl import load_workbook
# 获取用户上传的文件对象
file_object = request.FILES.get("exc")
# 对象传递给openpyxl, 由openpyxl读取文件的内容
wb = load_workbook(file_object)
# 读取第一个sheet
sheet = wb.worksheets[0]
# cell = sheet.cell(1, 1)
# 循环获取每一行的数据
for row in sheet.iter_rows(min_row=2):
# 获取每一行的第一个数据,即部门名称
text = row[0].value
# 判断该部门是否存在
exists = models.Department.objects.filter(title=text).exists()
if not exists:
models.Department.objects.create(title=text)
else:
return HttpResponse("上传失败,有重复名称的部门")
return redirect("/depart/list/")
案例:混合数据上传
提交页面时:用户输入数据 + 文件 (进行校验 不能为空,格式错误等)
- Form生成HTML标签:type=file
- 可以做表单的验证
- form.cleaned_data获取 数据 + 文件对象
{% extends "layout.html" %}
{%load static%}
{% block title %}
{{ title_templ }}
{% endblock %}
{% block Form上传 %}class="active"{% endblock %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ panel_title_templ}}</h3>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color:red;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> 保 存</button>
<a href="{{cancel_url}}" class="btn btn-danger" ><i class="fa fa-close" aria-hidden="true"></i> 取 消</a>
</form>
</div>
</div>
</div>
{% endblock %}
from django import forms
class UpForm(BootStrapForm):
bootstrap_exclude = ["img"]
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
import os
from app01 import models
def upload_form(request):
context = {"title_templ": "Form上传", "panel_title_templ": "Form上传"}
if request.method == "GET":
form = UpForm()
return render(request, "upload_form.html", {**context, "form": form})
# 进行表单验证要分别对数据和files进行验证
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# print(form.cleaned_data)
# {'name': 'wupeiqi', 'age': 12, 'img': <InMemoryUploadedFile: a1.png (image/png)>}
# 读取字段的数据然后分别对每个字段进行处理
img_object = form.cleaned_data.get("img")
# file_path = "app01/static/img/{}".format(img_object.name) project6-Django\System_Manage_User\app01\static
# 数据库上传的地址,是在网页端通过与服务器地址拼接可以直接访问的
db_file_path = os.path.join(
"static",
"img",
img_object.name,
)
# 实际上文件的地址,即在存储图片时候的地址
file_path = os.path.join(
"project6-Django", "System_Manage_User", "app01", db_file_path
)
f = open(file_path, mode="wb")
for chunk in img_object.chunks():
f.write(chunk)
f.close()
# 将图片路径写入数据库
models.Boss.objects.create(
name=form.cleaned_data["name"],
age=form.cleaned_data["age"],
img=db_file_path,
)
return HttpResponse("上传成功")
return render(request, "upload_form.html", {**context, "form": form})
2.2 启用media
在urls.py中进行配置
from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings
urlpatterns = [
re_path(r"^media/(?P<path>.*)$", serve, {"document_root":settings.MEDIA_ROOT}, name="media"),
]
在settings.py中进行配置
import os
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
之后就可以直接通过/media/图片.png访问图片
案例:混合数据上传(Form)
def upload_form(request):
context = {"title_templ": "Form上传", "panel_title_templ": "Form上传"}
if request.method == "GET":
form = UpForm()
return render(request, "upload_form.html", {**context, "form": form})
# 进行表单验证要分别对数据和files进行验证
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
from django.conf import settings
# media_path = os.path.join(settings.MEDIA_ROOT, img_object.name) 绝对路径
media_path = os.path.join("media", img_object.name)
# 实际上文件的地址,即在存储图片时候的地址
file_path = os.path.join("project6-Django", "System_Manage_User", media_path)
f = open(file_path, mode="wb")
for chunk in img_object.chunks():
f.write(chunk)
f.close()
# 将图片路径写入数据库
models.Boss.objects.create(
name=form.cleaned_data["name"],
age=form.cleaned_data["age"],
img=media_path,
)
return HttpResponse("上传成功")
return render(request, "upload_form.html", {**context, "form": form})
2.3modelform
models.py
class City(models.Model):
"""城市"""
name = models.CharField(verbose_name="名称", max_length=32)
count = models.IntegerField(verbose_name="人口")
# 本质上数据库中也是CharField,但是在保存时候
img = models.FileField(
verbose_name="LOGO", max_length=128, upload_to="city/"
) # 自动放到media下的city目录中
小结
-
自己动手写
file_object = request.FILES.get("exc")
-
Form组件(表单验证)
request.POST file_object = request.FILES.get("exc") 具体文件操作需要手动
-
ModelForm(表单验证 + 自动保存数据库 + 自动保存文件)
- Media文件夹 - Models.py定义类文件要 img = models.FileField(verbose_name="", max_length=128, upload_to="fileAddress/")