一、上传图片并在前端展示

为了避免前端整体刷新,我们采用ajax+iframe(兼容所有浏览器)上传,这样用户上传之后就可以立即看到图片:

上传前:

上传后:

前端部分html:

<form style="display: inline-block" id="upload_img_form" name="form" action="/upload/" method="POST"
enctype="multipart/form-data">
{% csrf_token %}
  <a id="fakeFile" class="fake-file">
    <input type="file" name="img" onchange="UploadImage(this);"/>
    <input type="text" name="url" class="hide"/>
</a>
<iframe id='upload_img_iframe' name='upload_img_iframe' src="" class="hide"></iframe>
</form>

  别看这么短短的html,坑却不少:

  • 坑one:action="/upload/",当年笔者傻傻的就只写了action="/upload",因为url是这么配的:url(r'^upload', v.upload),结果

    django居然报错了,笔者查了很多资料,最后才知道,原来,虽然url的最后没有加'/',但是django在运行时会自动给url的后面加'/',因此,我们在post提交时,必须在url的最后加'/'。

  • 坑two:enctype="multipart/form-data",文件上传相对于其他表单类型出现的概率比较小,而文件上传确是这些表单类型中的异类,它需要在form写上enctype="multipart/form-data"。
  • 坑three:{% csrf_token %},django运行程序时,请求首先会通过中间件,然后才会通过url,django配置文件中有关于跨站请求伪造的中间件:
    MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

      django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

    全局:

      中间件 django.middleware.csrf.CsrfViewMiddleware

    局部:

    • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
    • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

    中间件'django.middleware.csrf.CsrfViewMiddleware',会查看post请求是否携带token ,如果没有则直接在process_request中return 并报出如下错误:

    此时,我们有几种处理方式:1.直接简单粗暴的注释掉settings中的csrf中间件;2.给接收post请求的views函数加@csrf_exempt(注:from django.views.decorators.csrf import csrf_exempt,csrf_protect),该装饰器的意思是取消当前函数防跨站请求伪造功能;

JavaScript代码: 

function UploadImage(ths) {
document.getElementById('upload_img_iframe').onload = UploadImageComplete; //页面加载完成后执行UploadImageComplete函数
document.getElementById('upload_img_form').target = 'upload_img_iframe'; //设置form提交到iframe
document.getElementById('upload_img_form').submit(); //#提交到iframe
}
function UploadImageComplete() {
var origin = $("#upload_img_iframe").contents().find("body").text();//#获取图片数据
var obj = JSON.parse(origin); //#转换成JavaScript对象
var img = document.createElement('img'); //#创建img标签
img.src = obj.path; //图片地址
img.style.width = "200px";
img.style.height = "180px";
$("#upload_img_form").append(img);//添加图片
$('#fakeFile').addClass('hide');
$('#reUploadImage').removeClass('hide');
$('#fakeFile').find('input[type="text"]').val(obj.data);//#保存图片地址到隐藏的input标签中
}

  后台views函数代码:

def upload(request):
if request.method == 'POST':
obj = request.FILES.get('img')#获取图片对象
pat = os.path.join('static','img','vote',obj.name)#文件打开目录,需要和当前文件路径一致
f = open(pat,'wb')
for ch in obj.chunks():
f.write(ch)
f.close()
ret = {'path': '/'+os.path.join('static','img','vote',obj.name)}#django前端文件路径:'/' + 静态文件前缀static + 静态文件下的目录
import json
return HttpResponse(json.dumps(ret))#反馈给前端
return render(request,'upload.html',)

后台和前端js关于文件路径再现一坑:

  注:这里我们将图片保存在静态文件目录static下的img中(静态文件路径的前缀也是static)

  django前端我们希望的引入图片的路径是这样的:/static/img/xx.png,这里需要注意的是static前必须加'/',没错,就是这个神奇的'/',代表当前程序主目录,即配置文件中的BASE_DIR。

  后台我们打开文件写入图片到服务器的路径,这里open路径需要遵循的是python的规则而不是django前端的规则,即python会默认从当前路径开始找,因此直接static/img/xx.png就行,前面不需要加'/'。

二、数据库查询结果给前端反馈序列化的问题

  

  json不能序列化django中的datatime、Decimal等数据结构,解决方案:

1.单独转为python数据结构

str( Decimal('12.36'))

  然后通过json进行序列化。

2.直接将数据库查询结果QuerySet对象转化为列表,QuerySet看起来像列表

ret=list(QuerySet对象)
result=json.dumps(ret)

  由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

import json
from datetime import date
from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime):
return o.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, date):
return o.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field) # ds = json.dumps(d, cls=JsonCustomEncoder)

  这是通过制定json.dumps序列化的类来实现的。

3.使用django的序列化工具serializers

from django.core import serializers

ret = models.BookType.objects.all()

data = serializers.serialize("json", ret)

  总结:常见的form表单传文件可能大家都会,因此本博文主要讲述了ajax+iframe上传文件中需要注意的一些问题,如需form上传文件案例,可联系本人,谢谢!

  

  

那些年,我们在Django web开发中踩过的坑(一)——神奇的‘/’与ajax+iframe上传的更多相关文章

  1. 转:Flutter开发中踩过的坑

    记录一下入手Flutter后实际开发中踩过的一些坑,这些坑希望后来者踩的越少越好.本文章默认读者已经掌握Flutter初步开发基础. 坑1问题:在debug模式下,App启动第一个页面会很慢,甚至是黑 ...

  2. vuejs 开发中踩到的坑

    用 v-for 循环式  每个item的值相等的情况下,会影响v-model的双向绑定: Modal 组件开发,主要用slot 标签来实现 <template> <transitio ...

  3. vue项目开发中踩过的坑

    一.路由 这两天移动端的同事在研究vue,跟我说看着我的项目做的,子路由访问的时候是空白的,我第一反应是,不会模块没加载进来吧,还是....此处省略一千字... 废话不多说上代码 路由代码 { pat ...

  4. [译]如何在Web开发中使用Python

    [译]如何在Web开发中使用Python 原文:HOWTO Use Python in the Web 摘要 这篇文档展示了Python如何融入到web中.它介绍了几种Python结合web服务器的方 ...

  5. Django Web开发学习笔记(1)

    一.Python的标准类型 (1)bool型 >>> bool("") False >>> bool(None) False >>& ...

  6. Python Web开发中的WSGI协议简介

    在Python Web开发中,我们一般使用Flask.Django等web框架来开发应用程序,生产环境中将应用部署到Apache.Nginx等web服务器时,还需要uWSGI或者Gunicorn.一个 ...

  7. Django Web开发指南笔记

    Django Web开发指南笔记 语句VS表达式 python代码由表达式和语句组成,由解释器负责执行. 主要区别:表达式是一个值,它的结果一定是一个python对象:如:12,1+2,int('12 ...

  8. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  9. Web 开发中很实用的10个效果【附源码下载】

    在工作中,我们可能会用到各种交互效果.而这些效果在平常翻看文章的时候碰到很多,但是一时半会又想不起来在哪,所以养成知识整理的习惯是很有必要的.这篇文章给大家推荐10个在 Web 开发中很有用的效果,记 ...

随机推荐

  1. windows添加linux 启动引导项

    需要软件: EasyBCD 下载地址: http://pan.baidu.com/s/1c20v1GO 在windows 下安装上述软件. 然后打开,语言的话现在中文即可. 可以看到如下画面: 1.选 ...

  2. Citrix运行检测出错

    Citrix运行检测出错: 出现意外错误.请确认服务器名称正确.服务器已打开.Citrix XenApp 已安装在服务器上并且 Citrix MFCOM 服务正在运行. 看Windows日志出现如下错 ...

  3. java抓取快递100信息接口

    package zeze; import java.io.IOException; import org.json.JSONArray; import org.json.JSONException; ...

  4. 11.2---字符串数组排序,删除变位词(CC150)

    这道题主义的就是,要利用数组自带的sort函数. 此外,注意,利用hash来判断是否出现了. public static ArrayList<String> sortStrings(Str ...

  5. ubuntu安装文件比较工具Meld

    Meld是一款可视化的文件及目录对比(diff) / 合并 (merge) 工具,通过它你可以对两个或三个文件/目录进行对比,并以图形化的方式显示出它们的不同之处,同时还提供编辑及合并功能,另外还支持 ...

  6. ulimit命令

    原文链接 linux下默认是不产生core文件的,要用ulimit -c unlimited放开 概述 系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何在有限资源的条件 ...

  7. hdu 5442 (ACM-ICPC2015长春网络赛F题)

    题意:给出一个字符串,长度是2*10^4.将它首尾相接形成环,并在环上找一个起始点顺时针或逆时针走一圈,求字典序最大的走法,如果有多个答案则找起始点最小的,若起始点也相同则选择顺时针. 分析:后缀数组 ...

  8. (转)C++0x语言新特性一览

    转自:http://blog.csdn.net/zwvista/article/details/2429781 原文请见http://en.wikipedia.org/wiki/C%2B%2B0x. ...

  9. 内存管理_深入剖析volatile关键字

    四.深入剖析volatile关键字 在前面讲述了很多东西,其实都是为讲述volatile关键字作铺垫,那么接下来我们就进入主题. 1.volatile关键字的两层语义 一旦一个共享变量(类的成员变量. ...

  10. winrt获取文件MD5码

    //小文件 public static string ComputeMD5(byte[] bytes) { var alg = HashAlgorithmProvider.OpenAlgorithm( ...