目录
文件上传
(1)基本操作
初始化样例
urls,py
# ------------------上传文件---------------------------------------------------
path('upload/list/', upload.upload_list),
upload.py
from django.shortcuts import render,HttpResponse
def upload_list(request):
"""上传文件"""
if request.method == "GET":
return render(request,"upload_list.html")
print(request.POST)#请求体中的数据<QueryDict: {'csrfmiddlewaretoken': ['rUgQC4CEdv3vHiWc1v6z8M23TdYHYRNsy6mRqEeYA5HbhJWWz4lXaZNZQCHMAaN7'], 'username': ['123'], 'avator': ['a50f4bfbfbedab643b8ac351f636afc378311ea2.jpg']}>
print(request.FILES)#请求体发送过来的文件{<MultiValueDict: {}>}
return HttpResponse("---")
upload_list.html
{
% extends 'template.html' %}
{
% block content %}
<div class="container">
<form method="post">
{
% csrf_token %}
<input type="text" name="username">
<input type="file" name="avator">
<input type="submit" value="提交">
</form>
</div>
{
% endblock %}
访问页面
普通表单只能上传文件名称,不能上传文件内容
我们要在form标签中新加一个属性enctype="multipart/form-data
,才能上传图片文件
看到文件内容了
将上传的文件保存到本地
def upload_list(request):
"""上传文件"""
if request.method == "GET":
return render(request, "upload_list.html")
#print(request.POST) # 请求体中的数据<QueryDict: {'csrfmiddlewaretoken': ['rUgQC4CEdv3vHiWc1v6z8M23TdYHYRNsy6mRqEeYA5HbhJWWz4lXaZNZQCHMAaN7'], 'username': ['123'], 'avator': ['a50f4bfbfbedab643b8ac351f636afc378311ea2.jpg']}>
#print(request.FILES) # 请求体发送过来的文件{<MultiValueDict: {}>}
file_object = request.FILES.get("avator")
#print(file_object.name) # 文件名
f = open(file_object.name, mode='wb')
#将文件分块读取并保存在本地文件a1.png中
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("---")
可以看到项目文件已经写入了一张上传图片了
基本操作总结:
前端
后端
(2)上传Excel
案例1:批量上传
以部门模块为例进行修改
要进行Excel操作需要下载第三方库
pip install openpyxl
下面将会把Excel中的数据批量传到数据库中
1、准备一张Excel表格
前端添加
depart_list.html
<div class="panel panel-default">
<!-- 上传面板 -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
批量上传
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" action="/depart/multi/">
{
% csrf_token %}
<div class="form-group">
<input type="file" name="exc">
</div>
<input type="submit" value="上传" class="btn btn-info btn-sm">
</form>
</div>
</div>
后端
depart.py
def depart_multi(request):
"""批量上传Excel文件"""
#1、获取用户上传的文件对象
file_object = request.FILES.get("exc")
#print(type(file_object))
#直接打开Excel并读取内容
#from openpyxl import load_workbook
#2、对象传递给openpyxl,由openpyxl读取文件的内容
#wb = load_workbook("本地文件路径")
wb = load_workbook(file_object)
sheet = wb.worksheets[0]
#cell = sheet.cell(2,2)#获取sheet的一行一列
#print(cell.value)
#3、循环获取每行数据并添加到数据库
#sheet.rows()从第一行开始取
#sheet.iter_rows(min_row=2)#从第二行开始取(排除标题)
for row in sheet.iter_rows(min_row=2):
# print(row)
# (< Cell 'Sheet1'.A2 >,)
# (< Cell 'Sheet1'.A3 >,)
# (< Cell 'Sheet1'.A4 >,)
text = row[0].value
# print(text)
# 技术部
# 运营部
# 策划部
exists = models.Department.objects.filter(title=text).exists()
if not exists:
models.Department.objects.create(title=text)
return redirect("/depart/list/")
页面测试
上传文件
Excel批量上传总结
(3)Form上传
案例2:混合上传
适合
urls.py
path('upload/form/', upload.upload_form),
创建数据表
model.py
class Boss(models.Model):
"""老板"""
name = models.CharField(verbose_name="姓名",max_length=32)
age = models.IntegerField(verbose_name="年龄")
img = models.CharField(verbose_name="头像",max_length=128)
修改样式
BootStrap,py
class BootStrap:
#将不需要加BootStrap样式的排除掉
bootstrap_exclude_fields = [""]
def __init__(self, *args, **kwargs):
# 引用父类的ini方法
super().__init__(*args, **kwargs)
# 循环ModelForm中的字段,给每个字段的插件设置
for name, field in self.fields.items():
if name in self.bootstrap_exclude_fields:
continue
# 字段中有属性,保留原来属性,没有属性增加属性
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
form.py
class UpForm(BootStrapForm):
#将img加入bootstrap_exclude_fields列表可以排除它的样式
bootstrap_exclude_fields = ['img']
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
upload.py
def upload_form(request):
"""Form上传"""
title = "Form上传"
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {
'form': form, "title": title})
form = UpForm(data=request.POST, files=request.FILES) # 提交的数据既有文件还有表单
if form.is_valid():
# print(form.cleaned_data)
# {'name': '刘备', 'age': 123, 'img': <InMemoryUploadedFile: 黑曼巴.jpg (image/jpeg)>}
# 1、读取图片内容,写入到文件夹中并获取文件的路径。
image_object = form.cleaned_data.get("img")
# file_path = "app01/static/img/{}".format(image_object.name)
#存储到项目静态文件(缺点:无法给用户查看)
file_path = os.path.join("app01", "static", "img", image_object.name)
f = open(file_path,mode='wb')
for chunk in image_object.chunks():
f.write(chunk)
f.close()
#为了将图片能让用户看到,不能将app01拼接到路径中,而路径应该是“域名/static/img/图片名”
db_file_path = os.path.join("static", "img", image_object.name)
# 2、将能让用户看到的图片文件的路径写入到数据库。
models.Boss.objects.create(
name=form.cleaned_data["name"],
age=form.cleaned_data["age"],
img=db_file_path,
)
imgtest = models.Boss.objects.filter(id=2).first().img
return render(request, 'upload_form.html', {
"form": form, "title": title,"imgtest":imgtest})
#return HttpResponse("……")
return render(request, 'upload_form.html', {
"form": form, "title": title})
upload_form.html
{
% extends 'template.html' %}
{
% block content %}
<div>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"> {
{
title }} </h3>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" novalidate>
{
% csrf_token %}
{
% for obj in form %}
<div class="form-group">
<label> {
{
obj.label }} </label>
{
{
obj }}
<span style="color:red"> {
{
obj.errors.0 }}</span>
</div>
{
% endfor %}
<button type="submit" class="btn btn-primary"> 提交</button>
</form>
</div>
</div>
<div class="container">
<div class="page-header">
展示头像
</div>
<div class="panel-body">
<img src="http://127.0.0.1:8000/{
{ imgtest }}">
</div>
</div>
</div>
</div>
{
% endblock %}
访问页面
数据库
案例2文件上传改进(使用media)
启用media
from django.urls import path,re_path
from django.conf import settings
from django.views.static import serve
urlpatterns = [
re_path(r'^media/(?P<path>.*)$',serve,{
'document_root':settings.MEDIA_ROOT},name='media'),
]
import os
#这两句放在最下面
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
MEDIA_URL = "/media/"
新建media目录
通过url可以直接访问到media下面的图片
对之前图片上传的路径进行修改
此时进行上传,数据库中存放的是绝对路径
修改项目相对路径
#media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
media_path = os.path.join("media", image_object.name)
重新上传
upload.py
def upload_form(request):
"""Form上传"""
title = "Form上传"
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {
'form': form, "title": title})
form = UpForm(data=request.POST, files=request.FILES) # 提交的数据既有文件还有表单
if form.is_valid():
# print(form.cleaned_data)
# {'name': '刘备', 'age': 123, 'img': <InMemoryUploadedFile: 黑曼巴.jpg (image/jpeg)>}
# 1、读取图片内容,写入到文件夹中并获取文件的路径。
image_object = form.cleaned_data.get("img")
#media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
media_path = os.path.join("media", image_object.name)
f = open(media_path,mode='wb')
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2、将能让用户看到的图片文件的路径写入到数据库。
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', {
"form": form, "title": title})
(4)ModelForm上传
案例3:混合上传
修改一下导航栏
template.html
{
% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{
% block title_content %}
{
% endblock %}
</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
</head>
<body>
<!--导航-->
<div class="bs-example" data-example-id="inverted-navbar">
<nav class="navbar navbar-inverse">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-9" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/pretty/list/">靓号管理系统</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-9">
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">功能管理 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/depart/list/">部门管理</a></li>
<li><a href="/user/list/">用户管理</a></li>
<li><a href="/pretty/list/">靓号管理</a></li>
<li><a href="/task/list/">任务管理</a></li>
<li><a href="/order/list/">订单管理</a></li>
</ul>
</li>
<li><a href="/admin/list/">管理员账户</a></li>
<li><a href="/chart/list/">数据统计</a></li>
<li><a href="/chart/highcharts/">highcharts示例</a></li>
<li><a href="/upload/list/">Excel上传</a></li>
<li><a href="/upload/form/">Form上传</a></li>
<li><a href="/upload/modelform/">ModelForm上传</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="/login/">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{
{
request.session.info.name }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人资料</a></li>
<li><a href="#">我的信息</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout/">注销</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</div>
{
% block content %}{
% endblock %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
{
% block js %}{
% endblock %}
</body>
</html>
urls,py
path('upload/modelform/', upload.upload_modelform),
models.py
class City(models.Model):
"""城市"""
name = models.CharField(verbose_name="名称",max_length=32)
count = models.IntegerField(verbose_name="人口")
#FileField本质上也是CharField,可以自动保存数据,还能自动上传到media目录(media/city)
img = models.FileField(verbose_name="Logo",max_length=128,upload_to='city/')
makemigrations
migrate
form,py
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = models.City
bootstrap_exclude_fields = ['img']
fields = "__all__"
upload.py
def upload_modelform(request):
"""ModelForm上传文件和数据"""
title="ModelForm上传"
if request.method == "GET":
form = UpModelForm()
return render(request, 'upload_modelform.html',{
"title":title,'form':form})
form = UpModelForm(data=request.POST,files = request.FILES)
if form.is_valid():
#对应文件自动保存
#字段+上传路径写入到数据库
form.save()
return HttpResponse("成功!")
return render(request, 'upload_modelform.html', {
"title": title, 'form': form})
upload_modelform.html
{
% extends 'template.html' %}
{
% block content %}
<div>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"> {
{
title }} </h3>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" novalidate>
{
% csrf_token %}
{
% for obj in form %}
<div class="form-group">
<label> {
{
obj.label }} </label>
{
{
obj }}
<span style="color:red"> {
{
obj.errors.0 }}</span>
</div>
{
% endfor %}
<button type="submit" class="btn btn-primary"> 提交</button>
</form>
</div>
</div>
</div>
</div>
{
% endblock %}
小结
添加显示页面
urls.py
# 城市列表
path('city/list/', city.city_list),
path('city/add/', city.city_add),
city.py
from django.shortcuts import render, redirect
from app01.utils.pagination import Pagination
from app01 import models
from app01.utils.form import UpModelForm
def city_list(request):
"""城市列表"""
queryset = models.City.objects.all()
page_object = Pagination(request, queryset)
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.html(),
}
return render(request, "city_list.html", context)
def city_add(request):
"""添加城市"""
title = "新建城市"
if request.method == "GET":
form = UpModelForm()
return render(request, 'upload_modelform.html', {
"title": title, 'form': form})
form = UpModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对应文件自动保存
# 字段+上传路径写入到数据库
form.save()
return redirect("/city/list/")
return render(request, 'upload_modelform.html', {
"title": title, 'form': form})
city_list.html
{
% extends 'template.html' %}
{
% block content %}
<div>
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="/city/add/">
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建城市
</a>
</div>
<!--表格面板-->
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
城市列表
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Logo</th>
<th>名称</th>
<th>人口</th>
</tr>
</thead>
<tbody>
{
% for obj in queryset %}
<tr>
<th>{
{
obj.id }}</th>
<td>
<img src="/media/{
{ obj.img }}" style="height: 60px;">
</td>
<td>{
{
obj.name }}</td>
<td>{
{
obj.count }}</td>
</tr>
{
% endfor %}
</tbody>
</table>
</div>
<ul class="pagination">
{
{
page_string }}
</ul>
</div>
</div>
{
% endblock %}
访问页面
(5)完结散花
这个案例级项目终于跟着做完了,大概用了十五天时间,受益匪浅,有机会做几个企业级项目,在此真的非常非常感谢武老师!!!
视频链接