Django与Vue之间的数据传递

2017-10-17

用vue或者说写前端页面,最重要的一个问题,就应该是解决前端与后端的数据交换的问题,或者前端页面传递给后端页面,或者后端函数处理后返回给前端。如果能熟练解决这个问题,那就已经走了一大步。
我做目前的这个项目,一步一步摸索着走,踩了一些坑。在这里总结下:

问题1:django模板与vue的冲突。

比如在vue中添加data数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
},
methods:{
great:function(){
console.log('xixi')

}
}

})

这样有了两个数据,按照官方文档的说法是,在html中用这样就能获取到items的数据。
但现实情况是数据并不能找到,在用开发者工具的vue(需要单独安装)查看,是有数据的,说明数据已经生成,但是在html中就是不能引用到,而且没有报错信息。

这就是最不好解决的bug,没有报错信息。后来问了前端大牛,得知是和Django有冲突,后来在这篇文章中找到了解决方案。

django模板与vue.js的变量都是使用“”包裹起来的

我使用的是其中的方法3,这个方法的原理是和之间的部分,Django不对其进行渲染。然后就可以留给Vue来渲染了。

1
2
3
{% verbatim %}
{{ vue }}
{% endverbatim %}

问题2:Django的数据传递给Vue

Vue.js中的js中的数据能够传递给html,能够在视图中显示出来了。那js中的数据是从哪来的,这就涉及到与后台的交互了,需要从后台拿到数据。
首先是Django中有数据的部分:

1
2
3
4
5
6
7
8
def home(request):
List=[{'age':18},200]
OBJ={"name":"隔壁老王"}

return render(request, 'add_files.html',{
'list':json.dumps(List),
'obj':json.dumps(OBJ)
})

传递数据是用json传递过去的,否则会报错,所以需要用dumps处理成json数据格式。Vue中的代码接收代码为:

1
2
3
4
5
6
7
8
9
<!doctype html>
<html lang="en">
<head></head>
<body></body>
<script>
var list = {{ list | safe }}
var obj = {{ obj | safe }}
</script>
</html>

需要用这种格式才能接收到。代码参考自Django + Vue 单页面应用的开发环境搭建步骤

问题3:Vue传递数据给Django

既然是交互,就应该是相互的。后端接收前端的操作反馈然后调用函数进行处理是一个很常见的场景。所以需要将前端数据发给后端。我最开始想法是,前端能够之间调用后端的函数,比如说按钮的响应事件就能够和后端的函数直接进行绑定。后来发现暂时我的这种想法还是不太现实。那现实的情况是:

用post!,也就是说进行http请求,听说vue-resouse以后官方不再进行维护了,尤雨溪推荐用axios来代替。关于axios可以参考github文档,也可以参考这篇文章axios全攻略
直接把其中的下面的代码放到method的对应的函数中即可,然后在把路由改改

1
2
3
4
5
6
7
8
9
10
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

但如果那样会提示这样的错误

You called this URL via POST, but the URL doesn’t end in a slash and you have APPEND_SLASH set. Django can’t redirect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/add/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings.

解决这个问题,我是通过这篇文章找到的解决方案

1
2
3
4
5
First, make sure that you send the request to http://127.0.0.1/add/
 not http://127.0.0.1/add

Secondly, you may also want to exempt the view from csrf processing by adding the `@csrf_exempt
`decorator - since you aren't sending the appropriate token from cURL.

一个原因是在地址的后面加”/“,如果不加,Django是要寻找外网的地址。第二是要加上 @csrf_exempt,这个在哪里加?参考这篇文章跨站请求伪造保护-Django官方文档

1
2
3
4
5
6
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')

举例代码如上,这个装饰器的意义就是用来标记此部分不受保护。

问题4:关于render和HttpResponse的使用

接上面那个问题,这时后台已经能够收到js发来的数据,想要处理之后重新返回给前端,但是这时候,我用问题2的方法,返回给前端的是一个html数据,并不是一个数组。最后通过HttpResponse这个方法Django 前后台的数据传递给解决了

1
2
3
4
5
6
@csrf_exempt
def newmodle(request):
aa={"a":"aa","b":"bb"}
if request.method =='POST':
return HttpResponse(json.dumps(aa))
print request.body

这样处理后,在前端

1
2
3
4
5
6
7
8
9
axios.post('/newmodle/', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {

console.log(response)

})

就可以接收到数据了。写到这里我发现,可能和用render和HttpResponse没关系,可能我刚开始是用

1
2
var aa={{aa | safe}}
console.log(aa)

这样来获取数据的,这样是不能获取到的,后来我就直接打印的response,这个可能和这里有关系。

参考文章:

django模板与vue.js冲突问题
Django + Vue 单页面应用的开发环境搭建步骤
跨站请求伪造保护-Django官方文档
Django 前后台的数据传递