Mapz's Blog

可以递归的函数指针

Django项目开发(三)结合Vue

原文地址:Mapz的blog

前文目录:

  1. Django项目的搭建
  2. Django项目开发(一)
  3. Django项目开发(二)View层

前面我们介绍了Django的一些基本安装和使用

因为我们项目将会使用前后端分离的技术来处理,所以我们将会放弃使用Django的View层来处理业务逻辑,而只是用Django做ORM和API接口,并使用 Vue.js 2 来制作前端页面


Vue.js 简介

MVVM

Vue 采用 MVVM 的模式,MVVM 是 MVC 的衍生物

他和 MVC 的区别在哪儿呢

在 MVVM 中 C 变成了 VM

在 MVC 中用户可以直接操作 C 层 或是通过 V 层来操作 Model

C 层一般只有路由的作用 而 V 层则承载了大量的业务逻辑,非常臃肿

而在 MVVM 中 View 和 Model 之间不再直接发生关系了

View 层也不在有任何业务逻辑,他是真的只作为展示层来使用

逻辑去了哪儿呢?答案是 VM 层,就是 ModelView

然后为什么说 MVVM 可以方便的实现数据和逻辑分离呢

关键在 VM 层和 M 层是双向绑定的

也就是说,我在 VM 层经过逻辑处理的数据,会自动表现在 View 层上,也会自动改变 Model 层中的数据

于是我们的数据、逻辑和渲染,就完全分开了

简而言之:

我只需要修改好我的业务逻辑,配置好数据,写好模版,所有的一切就可以自动呈现和更新了

业务逻辑,数据和展示真正做到了分离

Vue.js

Vue React Angular 都是最近比较流行的前端框架

数据的双向绑定,响应式和组件化 都是他们的思维要点

Vue 相比另两个,优点是学习成本低,性能高,并且虽然比不上另外两个,但任然有着比较丰富的生态

另外 Vue 还有他的原生兄弟 Weex

Weex 是阿里的跨平台用户界面开发框架,他兼容 Vue 的语法

也就是说

学会 Vue 之后,你也可以让你的代码跑上 iOS 和 Android

当然啦,React 也有对应的 ReactNative 来做原生应用


集成 Vue 到 Django 中

我们假定你的机器上已经装好了

  • Node.js 4+
  • npm 3+
  • Python 2.7+

以下安装需要基于上述环境

安装 vue-cli

vue 一般使用 vue-cli 来初始化我们的项目

1
npm i vue-cli -g --registry=https://registry.npm.taobao.org

-g 的意思是全局安装

–registry 参数是镜像,我们在国内一般用淘宝的镜像比较快

创建 vue 项目

回到我们的django项目的目录下,用vue-cli 创建一个项目

1
vue-init webpack frontend

其中 frontend 是我们的 vue 工程目录名称

中间的参数是我们要用到的模版

1
npm run build

这个命令可以导出webpack输出,简单说就是web工程打包

build 好的内容导出 dist 目录下,也就是我们django中要用到的内容了

Django下的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# settings.py 需要加载模版,所以要修改我们的模版目录加上dist目录
TEMPLATES = [
{
...
'DIRS': ['frontend/dist/'],
...
},
]

...

# 让Django能去dist下寻找静态文件
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "frontend/dist/static"),
]

# qk_deploy/urls.py
from django.views.generic import TemplateView

# 将我们的文件直接作为模版引入
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name="index.html"))
]

我们现在访问

http://127.0.0.1:8000/qk_deploy/#/

应该可以看到 vue 的欢迎页面了

搭建调试环境

如果我们使用 Django的环境来进行测试呢,也就会导致,每次修改了vue项目的文件都要重新build,这样太慢了

vue.js的开发环境会自动检查文件变化来重新构建,是比较方便的

1
npm run dev

会启动vue的开发环境,但这样有个问题,使用vue的开发环境,就是脱离了Django的开发环境了,访问Django上的API出现了跨域问题

为了能让我们快乐的调试呢,我们使用Django的第三方插件django-cors-headers来解决跨域问题

1
pip install django-cors-headers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# settings.py
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', #注意顺序不能变
'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',
]

...

CORS_ORIGIN_ALLOW_ALL = True #添加这个配置

Django 配置 RESTful API

不用Django的后端渲染了,我们使用RESTful API作为前后端交流的工具

安装 djangorestframework 

1
2
3
pip install djangorestframework -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install markdown -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install django-filter -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

这里我们和 npm 安装东西的时候一样,使用了镜像,不然下载的太慢了啦 pip 使用镜像用-i参数
对于不是https的地址,必须用 –trusted-host 才能继续

装好后

1
2
3
4
5
6
7
8
9
10
11
# settings.py
INSTALLED_APPS = (
...
'rest_framework',
)

# 项目根目录下 url.py
urlpatterns = [
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

创建model和serializer

我们这里将用用户登陆为例,来看怎么写和使用API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# views.py
from .serializers import *
from rest_framework import permissions,status
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.authentication import BasicAuthentication

class UserLogin(generics.CreateAPIView):
permission_classes = (permissions.AllowAny,)
serializer_class = LoginSerializer
authentication_classes = (BasicAuthentication,) #这里一定要是 BasicAuthentication,否则会出现CSRF问题,因为我们现在是登陆,登录前么有在session中用CSRF,这个问题我们后面来说

def post(self, request, *args, **kwargs):
try:
username = request.data.get('username')
print(username)
password = request.data.get('password')
print(password)
user = User.objects.get(username__iexact=username)
print(user)
if user.check_password(password):
serializer = LoginSerializer({'id': user.id, 'username': user.username})
return Response(serializer.data)
return Response(status=status.HTTP_401_UNAUTHORIZED)
except User.DoesNotExist:
return Response(status=status.HTTP_401_UNAUTHORIZED)

创建我们的登陆view

创建serializers.py

1
2
3
4
5
6
7
8
9
10
11
12
#coding:utf-8
from django.contrib.auth.models import User
from rest_framework import serializers

class LoginSerializer(serializers.ModelSerializer):

username = serializers.CharField(required=False, max_length=1024)
password = serializers.CharField(required=False, max_length=1024)

class Meta:
model = User
fields = ('id', 'username', 'password')

urls.py中加上

1
2
3
4
urlpatterns = [
...
url(r'^api/login$', UserLogin.as_view()),
]

访问

http://127.0.0.1:8000/qk_deploy/api/login

可以看到 restful_framework的测试界面

在界面测试API

用已有的用户登陆,已经可以看到正确的回应了,否则会返回状态401