django文件上传下载

上传

配置settings.py

# 设定文件的访问路径,如:访问http://127.0.0.1:8000/media/就可以获取文件
MEDIA_URL = '/media/'
# 设置文件的存储路径,全部存储在media目录下,会和model类中的upload_to属性值拼接
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

models.py

class Img(models.Model):
name = models.CharField(max_length=32)
# upload_to拼接在MEDIA_ROOT后面,../media/img/article/,内容均存在该目录下
img = models.ImageField(upload_to='img/article/',verbose_name='图片')

upload.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--enctype属性值修改成"multipart/form-data"-->
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<!--type类型要改成file,文件类型-->
<input type="text" name="name">
<input type="file" name="img">
<button>上传</button>
</form>
</body>
</html> <!--多文件上传-->
<input type="file" name="myfiles" multiple="">

views.py

# 获取上传文件单个插入数据
def upload(request): if request.method == 'POST':
# 获取文件名称
img_url = request.FILES.get("img")
name = request.POST.get("name")
# 存到数据库中,并保存到指定的目录下
img = models.Media(name=name,img=img_url)
img.save() return render(request,"youhua.html") # 获取上传文件插入批量数据
def upload(request):
if request.method == 'POST':
img_list = request.FILES.getlist('img')
name = request.POST.get("name")
querysetlist = []
for img in img_list:
querysetlist.append(models.Media(name=name,img=img))
models.Media.objects.bulk_create(querysetlist) return HttpResponse("上传成功") return render(request, "youhua.html")

ajax上传图片

FormData上传

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<input type="file" name="img" id="img">
<input type="button" value="上传" onclick="showImg();">
<script type="text/javascript">
function showImg() {
var formdata = new FormData();// 创建一个空的FormData对象,可以使用formdata.append(key,value)来添加数据。
formdata.append('file', document.getElementById('img').files[0]);
$.ajax({
url: '/upload/',
type: 'post',
headers :{
'x-csrftoken': '{{ csrf_token }}', // 为了通过csrf校验,所以必须带这个过去。
},
data: formdata,
// 默认值为true,默认会将发送的数据序列化以适应默认的内容类型。不想转换信息,需要设置为false
// 此数据传输的是对象,所以不需要序列化
processData: false,
// 不写默认为application/x-www-form-urlencoded只能上传文本,上传文件需要用multipart/form-data类型。
contentType: false, // 不设置内容类型
success: function (data) {
alert(data)
}
});
}
</script>
</body>
</html>

views.py

def upload(request):
if request.method == 'POST':
img_url = request.FILES.get('file')
img = models.Media(name='hello',img=img_url)
img.save()
ret = '上传成功'
return HttpResponse(ret) return render(request,"youhua.html")

页面展示图片

如果涉及到下载/显示资源,就需要添加url

from django.contrib import admin
from django.urls import path
from imgTest.views import uploadImg, showImg
from django.conf.urls.static import static
from django.conf import settings # 写法一
urlpatterns = [
path('admin/', admin.site.urls),
path('upload/', upload),
path('showImg/', showImg)
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # 写法二
from django.views.static import serve
urlpatterns = [
...
path('showImg/', showImg),
url('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
]

views.py

def showImg(request):
obj_list = models.Img.objects.all()
print(obj_list) return render(request,'showImg.html',{"obj_list":obj_list})

showImg.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for obj in obj_list %}
<!--必须要带url,不然路径会错误-->
<img src="{{ obj.img.url }}" alt="">
{% endfor %}
</body>
</html>

文件下载

自定义编写视图下载方法,主要是为了限制用户的下载内容,一定要注意限制用户的下载内容,不然知道路径连代码和数据库都下载了。

urls.py

from app_youhua import views

urlpatterns = [
# ......
url('^download/(?P<pk>\d+)/$', views.download, name='download'),
]

html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
</head>
<body>
{% for obj in obj_list %}
<img src="{{ obj.img.url }}" alt=""> <!--自动将数据库中的图片全部显示,可以自定制拼接路径-->
<a href="{% url 'download' obj.pk %}">下载</a> <!--url反向解析-->
{% endfor %} </body>
</html>

使用HttpResponse

from django.http import HttpResponse, Http404

def download(request, pk=None):
obj = models.Media.objects.get(pk=pk)
filename = str(obj.img)
filepath = os.path.join(settings.MEDIA_ROOT, filename)
   with open(filepath, 'rb') as f:
       try:
           response = HttpResponse(f)
           response['content_type'] = "application/octet-stream"
           response['Content-Disposition'] = 'attachment; filename=%s' % filename
           return response
       except Exception:
           raise Http404

HttpResponse有个很大的弊端,其工作原理是先读取文件,载入内存,然后再输出。如果下载文件很大,该方法会占用很多内存。对于下载大文件,Django更推荐StreamingHttpResponse和FileResponse方法,这两个方法将下载文件分批(Chunks)写入用户本地磁盘,先不将它们载入服务器内存。

使用StreamingHttpResponse和FileResponse

from django.http import FileResponse, StreamingHttpResponse

def download(request, pk=None):
obj = models.Media.objects.get(pk=pk)
filename = str(obj.img)
# filename = request.GET.get('file') # 如果文件名直接通过页面传回
filepath = os.path.join(settings.MEDIA_ROOT, filename)
# 文件将会自动关闭,所以不需要使用with语句打开文件
fp = open(filepath, 'rb')
response = StreamingHttpResponse(fp)
# response = FileResponse(fp) # 默认一次下载4096字节
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="%s"' % filename
return response

文件私有化的两种方法

如果你想实现只有登录过的用户才能查看和下载某些文件。

  • 上传文件放在media文件夹,文件名使用很长的随机字符串命名(uuid), 让用户无法根据文件名猜出这是什么文件。视图和模板里验证用户是否已登录,登录或通过权限验证后才显示具体的url。- 简单易实现,安全性不高,但对于一般项目已足够。

  • 上传文件放在非media文件夹,用户即使知道了具体文件地址也无法访问,因为Django只会给media文件夹里每个文件创建独立url资源。视图和模板里验证用户是否已登录,登录或通过权限验证后通过自己编写的下载方法下载文件。- 安全性高,但实现相对复杂。

  • 我们定义的下载方法可以下载所有文件,不仅包括.py文件,还包括不在media文件夹里的文件(比如非用户上传的文件)。比如当我们直接访问127.0.0.1:8000/file/download/file_project/settings.py/时,你会发现我们连file_project目录下的settings.py都下载了。

# 简单举例,不让用户下载.py等结尾的文件
from django.http import Http404,FileResponse, StreamingHttpResponse
def download(request, pk=None):
obj = models.Media.objects.get(pk=pk)
filename = str(obj.img)
filepath = os.path.join(settings.MEDIA_ROOT, filename)
ext = os.path.basename(file_path).split('.')[-1].lower()
   # cannot be used to download py, db and sqlite3 files.
   if ext not in ['py', 'db',  'sqlite3']:
# 文件将会自动关闭,所以不需要使用with语句打开文件
fp = open(filepath, 'rb')
response = StreamingHttpResponse(fp)
       response['content_type'] = "application/octet-stream"
       response['Content-Disposition'] = 'attachment;filename="%s"' % filename
       return response
   else:
       raise Http404

django富文本编辑框

下载

pip install django-ckeditor

注册

INSTALLED_APPS = [
...
'ckeditor',
'ckeditor_uploader',
]

settings中配置

CKEDITOR_UPLOAD_PATH = 'ckeditor/'

配置urls.py

from ckeditor_uploader import views
from django.views.static import serve urlpatterns = [
url(r'^media/(?P<path>.*)', serve, {'document_root':settings.MEDIA_ROOT}),
# 上传文件
url(r'^ckeditor/upload/', views.upload),
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
]

models.py使用富文本编辑框字段

from ckeditor_uploader.fields import RichTextUploadingField
class Article(models.Model):
title = models.CharField(max_length=32)
detail = models.OneToOneField('ArticleDetail',on_delete=models.CASCADE) class ArticleDetail(models.Model):
content = RichTextUploadingField(verbose_name='文章详情')

模板中使用

{{ field }} 使用ModelForm富文本编辑框的字段,
# 导入js样式,只要需要显示富文本编辑框就要导入
<script src="{% static 'ckeditor/ckeditor/ckeditor.js' %}"></script>
<script src="{% static 'ckeditor/ckeditor-init.js' %}"></script>

关联表同时显示富文本编辑框

比如:编辑内容时,肯定是连同关联的详情内容一同填写。

# 视图函数
def article_add(request):
# 对两个form表单进行实例化
form_obj = ArticleForm()
detail_form = ArticleDetailForm()
if request.method == 'POST':
# 先校验并保存被关联方
detail_form = ArticleDetailForm(request.POST)
if detail_form.is_valid():
detail_form.save()
qd = request.POST.copy() # request.POST是有序字典,默认是不可编辑,所以进行深拷贝后编辑
# 找到被关联方提交此条数据的pk
qd['detail'] = detail_form.instance.pk
# 校验并保存被关联方
form_obj = ArticleForm(data=qd, files=request.FILES) # 如存在文件类,需单独传参
if form_obj.is_valid():
form_obj.save()
return redirect(reverse('backend:article_list'))
# 如果被关联方未通过校验,且关联方通过校验并保存,则删除关联方保存的数据
if detail_form.is_valid() and detail_form.instance:
detail_form.instance.delete()
title = '新增文章'
return
render(request,'backend/article_form.html'{'form_obj':form_obj,'title':title,'detail_form':detail_form})
from django import forms
from repository import models class ArticleForm(forms.ModelForm):
class Meta:
model = models.Article
fields = '__all__' def __init__(self,*args,**kwargs):
super(ArticleForm, self).__init__(*args,**kwargs) for field in self.fields.values():
# 用来控制不使用'form-control'样式的
if isinstance(field.widget,forms.ClearableFileInput):
continue
field.widget.attrs['class'] = 'form-control' class ArticleDetailForm(forms.ModelForm):
class Meta:
model = models.ArticleDetail
fields = '__all__'

Django文件上传下载与富文本编辑框的更多相关文章

  1. django文件上传下载

    views: def mgmt_files(request): #列出树形目录,上传文件页面 if request.method == 'POST': path_root = "D:\\py ...

  2. django 12天(跨域,文件上传,下载,cookie,session)

    django 12天(跨域,文件上传,下载) 跨域 什么是跨域 1.协议不同 2.端口不同 3.主机不同 如何解决跨域 1.安装django-cors-headers模块 2.在settings.py ...

  3. java中的文件上传下载

    java中文件上传下载原理 学习内容 文件上传下载原理 底层代码实现文件上传下载 SmartUpload组件 Struts2实现文件上传下载 富文本编辑器文件上传下载 扩展及延伸 学习本门课程需要掌握 ...

  4. Struts的文件上传下载

    Struts的文件上传下载 1.文件上传 Struts2的文件上传也是使用fileUpload的组件,这个组默认是集合在框架里面的.且是使用拦截器:<interceptor name=" ...

  5. Android okHttp网络请求之文件上传下载

    前言: 前面介绍了基于okHttp的get.post基本使用(http://www.cnblogs.com/whoislcj/p/5526431.html),今天来实现一下基于okHttp的文件上传. ...

  6. Selenium2学习-039-WebUI自动化实战实例-文件上传下载

    通常在 WebUI 自动化测试过程中必然会涉及到文件上传的自动化测试需求,而开发在进行相应的技术实现是不同的,粗略可划分为两类:input标签类(类型为file)和非input标签类(例如:div.a ...

  7. 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)

    1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...

  8. 艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)(一)

    艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输) 该系统基于开源的networkComms通讯框架,此通讯框架以前是收费的,目前已经免费并开元,作者是英国的,开发时间5年多,框架很稳定. 项 ...

  9. ssh框架文件上传下载

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. selenium下拉一个框内的滚动条

    js='document.getElementsByClassName("route-tree")[0].scrollTop=10000'

  2. bzoj3991 [SDOI2015]寻宝游戏 树链的并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3991 题解 貌似这个东西叫做树链的并,以前貌似写过一个类似的用来动态维护虚树. 大概就是最终的 ...

  3. Linux下统计当前文件夹下的文件个数

    Linux下统计当前文件夹下的文件个数 √ ls -l |grep "^-"|wc -l

  4. LeetCode--049--字母异位词分组(java)

    给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", "tea", "tan&quo ...

  5. [LeetCode] 53. Maximum Subarray 最大子数组 --动态规划+分治

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  6. Mac Pro 安装win10记录(不用优盘版)

    用启动转换助理 就可以了提前下好win10 iso系统镜像文件,然后Mac会自动安装.然后一直下一步就可以了. 我这次装好之后无法连接网络,发现是因为win网卡驱动没有,所以回到Mac系统下 把需要的 ...

  7. springboot整合hibernate案例

    1.运行环境 开发工具:intellij idea JDK版本:1.8 项目管理工具:Maven 4.0.0 2.GITHUB地址 https://github.com/nbfujx/springBo ...

  8. Just Skip The Problem

    http://acm.hdu.edu.cn/showproblem.php?pid=6600 题意:给你一个数x,允许你多次询问yi,然后回答你x xor yi 是否等于yi,询问尽量少的次数以保证能 ...

  9. postman 简单使用教程

    Postman 安装   Postman 接口测试(Collection)   Postman 接口测试(测试用例)Postman 接口测试(变量与参数化)Postman 接口测试(非 UI 运行模式 ...

  10. 高级Javascript代码

    Javascript是一门很吊的语言,我可能学了假的JavaScript,哈哈,大家还有什么推荐的,补充送那啥邀请码. 本文秉承着:你看不懂是你SB,我写的代码就要牛逼. 1.单行写一个评级组件 &q ...