1. 上传文件相关字段类型
- FileField:上传文件
- FilePathField:服务器上的文件
- ImageField:上传图片
1.1. 注意!
- 一定要注意文件内容和格式!
- 务必对所有上传文件进行安全检查!
- 如果你不加任何检查就盲目的让任何人上传文件到你的服务器文档根目录内,比如上传了一个CGI或者PHP脚本,很可能就会被访问的用户执行,这具有致命的危害。
2. 基础设置步骤
2.1. 设置上传路径
- 设置 MEDIA_ROOT(settings.py)
- TEMPLATES 中 context_processors 添加: ‘django.template.context_processors.media’,
- MEDIA_ROOT 基本路径,注意读写权限 os.path.join(BASE_DIR, ‘folder/‘)
- MEDIA_URL 访问文件的路径,比如:MEDIA_URL = ‘/upload/‘
- 设置上传文件字段路径(models.py)
- 配置根 URLconf
from .settings import MEDIA_ROOTfrom django.views.static import servefrom django.conf.urls import urlurlpatterns=[#...url(r'^upload/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}),]
3. 示例
3.1. FileField 上传文件
3.1.1. 设置 upload_to 路径
class MyModel(models.Model):# 上传位置:MEDIA_ROOT/uploads/upload = models.FileField(upload_to='uploads/')# 上传位置:MEDIA_ROOT/uploads/2019/09/09/upload = models.FileField(upload_to='uploads/%Y/%m/%d/')
3.1.2. 回调函数上传
def user_directory_path(instance, filename):"""上传到用户路径Args:instance: 当前数据记录filename: 文件名Returns:str: Unix风格字符串"""# 上传位置:MEDIA_ROOT/user_<id>/<filename>return 'user_{}/{}'.format(instance.user.id, filename)class MyModel(models.Model):upload = models.FileField(upload_to=user_directory_path)
3.2. ImageField 上传图片
使用前需安装 Pillow:$ pip3 install pillow
与 FileField 相似,只是多了:
- height_field 参数:记录图片的高度
- width_field 参数:同上,记录宽度
3.3. 模板中使用
比如 ImageField 字段名叫:mug_shot
{{ objName.mug_shot.url }}文件URL{{ objName.mug_shot.name }}名称{{ objName.mug_shot.size }}大小
4. 上传文件提供有限的访问
- 根 URLconf 中设置的
url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}),只是在python manage.py runserver本地服务器中使用的 - 部署到IIS中就可以注释上面这一项
- 提供有限访问的方法
4.1. 提供有限访问的方法
比如,只想让拥有浏览下载权限的用户下载文件,其余的不可以下载
可以参考 使用StreamHttpResponse和FileResponse下载文件的注意事项及文件私有化
# 应用 urls.py#...urlpatterns = [#...path('serve_files/<int:file_id>/', fore.serve_files, name='serve_files'), # 提供媒体文件]# views.pyfrom django.http import FileResponse@permission_required('inna.view_download')def serve_files(request, file_id):"""提供文件只有查看下载权限的用户可以得到文件"""# 获取文件对象downloadable_file = get_object_or_404(Download, id=file_id)file_upload_list = downloadable_file.file_upload.url.split('/')file_name_list = file_upload_list[3].split('.')filename = file_name_list[0]ext = file_name_list[1]# 增加下载数downloadable_file.reader += 1downloadable_file.save()# 匹配 MIME 类型ext_content_type = {'xls': 'application/vnd.ms-excel','xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','doc': 'application/msword','docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document','pdf': 'application/pdf','stp': 'application/stp','step': 'application/stp','cad': 'application/cad',}file_path = os.path.join(settings.MEDIA_ROOT, 'download', filename +'.'+ ext)the_file = open(file_path, 'rb')file_response = FileResponse(the_file)file_response['content_type'] = ext_content_type[ext]file_response['Content-Disposition'] = 'attachment; filename=' + filename +'.'+ extreturn file_response
<!-- templates.html --><a target="_blank" href="{% url 'inna:serve_files' file.id %}">
