使用Django + Vue.js快速而优雅地构建前后端分离项目

Django与Vue.js是如何结合起来?

首先我选择了Vue.js的前端渲染,自然放弃了Django的后端模板引擎渲染。

然后业务逻辑放到了前端,放弃了Django的View(其实也就是前后端分离必要的条件)。

保留了Django的 Controller (URLconf) 来实现前端路由的父级路由,可以达到不同页面使用不同的前端框架, 页面内部使用各自独有的前端路由的效果,万一老大给你配了前端呢,万一前端只想写 ReactJS 呢?

保留了Django的 Model ,前面说了Django的ORM太好用了,而且可以配合Django Admin。

所以综合来说就是:

M(Django) + C(Django) + MVVM (Vue.js) = M + MVVM + C = MMVVMC

为了容易理解,并没有使用Django自称的MTV模式理解,感兴趣看看我画的图:

图片[1]-使用Django + Vue.js快速而优雅地构建前后端分离项目-JieYingAI捷鹰AI

代码块中的修改都会用爽星号括起来,比如: changed

说明:本文为了精简篇幅,默认您已经安装了必要的 命令行界面(CLI),比如 vue-cli等。

1. 创建Django项目

命令:

django-admin startproject ulb_manager

结构:

.
├── manage.py
└── ulb_manager
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

2. 进入项目根目录,创建一个 App 作为项目后端

命令:

cd ulb_manager
python manage.py startapp backend

即:App 名叫做 backend

结构:

.
├── backend
│   ├── __init__.py
│   ├── admin.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── ulb_manager
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

3. 使用vue-cli创建一个Vue.js项目作为项目前端

命令:

vue-init webpack frontend

即:项目名叫 frontend结构:

.
├── backend
│   ├── __init__.py
│   ├── admin.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── frontend
│   ├── README.md
│   ├── build
│   │   └── ....
│   ├── config
│   │   ├── dev.env.js
│   │   ├── index.js
│   │   ├── prod.env.js
│   │   └── test.env.js
│   ├── index.html
│   ├── package.json
│   ├── src
│   │   ├── App.vue
│   │   ├── assets
│   │   │   └── logo.png
│   │   ├── components
│   │   │   └── Hello.vue
│   │   └── main.js
│   ├── static
│   └── test
│       └── ...
├── manage.py
└── ulb_manager
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

结构总结:可以看到项目根目录有两个新文件夹,一个叫 backend ,一个叫 frontend,分别是:backend Django的一个App;frontend Vue.js项目。

4. 接下来我们使用 webpack 打包VusJS项目

命令:

cd frontend
npm install
npm run build

结构:

我引入了一些包,比如element-ui等,你的static里面的内容会不同,没关系 index.html 和 static 文件夹相同就够了。

dist
├── index.html
└── static
    ├── css
    │   ├── app.42b821a6fd065652cb86e2af5bf3b5d2.css
    │   └── app.42b821a6fd065652cb86e2af5bf3b5d2.css.map
    ├── fonts
    │   ├── element-icons.a61be9c.eot
    │   └── element-icons.b02bdc1.ttf
    ├── img
    │   └── element-icons.09162bc.svg
    └── js
        ├── 0.8750b01fa7ffd70f7ba6.js
        ├── vendor.804853a3a7c622c4cb5b.js
        └── vendor.804853a3a7c622c4cb5b.js.map

构建完成会生成一个 文件夹名字叫dist,里面有一个 index.html 和一个 文件夹static.

5. 使用Django的通用视图 TemplateView

找到项目根 urls.py (即ulb_manager/urls.py),使用通用视图创建最简单的模板控制器,访问 『/』时直接返回 index.html。

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    **url(r'^$', TemplateView.as_view(template_name="index.html")),**
    url(r'^api/', include('backend.urls', namespace='api'))
]

6. 配置Django项目的模板搜索路径

上一步使用了Django的模板系统,所以需要配置一下模板使Django知道从哪里找到index.html。

打开 settings.py (ulb_manager/settings.py),找到TEMPLATES配置项,修改如下:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 'DIRS': [],
        **'DIRS': ['frontend/dist']**,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

注意这里的 frontend 是Vue.js项目目录,dist则是运行 npm run build 构建出的index.html与静态文件夹 static 的父级目录这时启动Django项目,访问 / 则可以访问index.html,但是还有问题,静态文件都是404错误,下一步我们解决这个问题

7. 配置静态文件搜索路径

打开 settings.py (ulb_manager/settings.py),找到 STATICFILES_DIRS 配置项,配置如下:

# Add for Vue.js
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "frontend/dist/static"),
]

这样Django不仅可以将/ulb 映射到index.html,而且还可以顺利找到静态文件此时访问 /ulb 我们可以看到使用Django作为后端的Vue.js helloworldALL DONE。

8. 开发环境

因为我们使用了Django作为后端,每次修改了前端之后都要重新构建(你可以理解为不编译不能运行)。

除了使用Django作为后端,我们还可以在dist目录下面运行以下命令来看效果:

hs(即: http server)

图片[2]-使用Django + Vue.js快速而优雅地构建前后端分离项目-JieYingAI捷鹰AI

但是问题依然没有解决,我想过检测文件变化来自动构建,但是构建是秒级的,太慢了,所以我直接使用Vue.js的开发环境来调试。

npm run dev

图片[3]-使用Django + Vue.js快速而优雅地构建前后端分离项目-JieYingAI捷鹰AI

毫秒,但是有个新问题,使用Vue.js的开发环境脱离了Django环境,访问Django写的API,出现了跨域问题,有两种方法解决,一种是在Vue.js层上做转发(proxyTable),另一种是在Django层注入header,这里我使用后者,用Django的第三方包 django-cors-headers 来解决跨域问题。

安装

pip install django-cors-headers

配置(两步)

MIDDLEWARE = [
    '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.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

这里要注意中间件加载顺序,列表是有序的。

CORS_ORIGIN_ALLOW_ALL = True

至此,我的开发环境就搭建完成了。

9. 生产环境部署

接下来就是生产环境的部署了,例如,我们可以尝试将项目部署到UCloud云主机上:

注册 UCloud,找到主机管理列表,如下所示:

这里注意记住你的外网IP,下面的IP替换成你的。

9.2 环境搭建与部署

CentOS 系统可以使用 yum 安装必要的包。

如果你使用git来托管代码:

yum install git

如果你要在服务器上构建前端:

yum install nodejs
yum install npm

yum install nginx

我们使用 uwsgi 来处理 Django 请求,使用 nginx 处理 static 文件(即之前 build 之后 dist 里面的static,这里默认前端已经打包好了,如果在服务端打包前端需要安装nodejs,npm等)。

安装uWsgi:

yum install uwsgi

或者:

pip install uwsgi

我们使用配置文件启动uwsgi,比较清楚。

uwsgi配置文件::

[uwsgi]
socket = 127.0.0.1:9292
stats = 127.0.0.1:9293
workers = 4

项目根目录:

chdir = /opt/inner_ulb_manager
touch-reload = /opt/inner_ulb_manager
py-auto-reload = 1

在项目跟目录和项目同名的文件夹里面的一个文件

module= inner_ulb_manager.wsgi
pidfile = /var/run/inner_ulb_manager.pid
daemonize = /var/log/inner_ulb_manager.log
nginx 配置文件:
server {
    listen 8888;
    server_name 120.132.**.75;
    root /opt/inner_ulb_manager;
    access_log /var/log/nginx/access_narwhals.log;
    error_log /var/log/nginx/error_narwhals.log;
    location / {
            uwsgi_pass 127.0.0.1:9292;
            include /etc/nginx/uwsgi_params;
    }
    location /static/ {
            root  /opt/inner_ulb_manager/;
            access_log off;
    }
    location ^~ /admin/ {
            uwsgi_pass 127.0.0.1:9292;
            include /etc/nginx/uwsgi_params;
    }
}

/opt/inner_ulb_manager/static 即为静态文件目录,那么现在我们静态文件还在 frontend/dist 怎么办,不怕,Django给我们提供了命令:

先去settings里面配置:

STATIC_ROOT = os.path.join(BASE_DIR, "static")

然后在存在manage.py的目录,即项目跟目录执行:

python manage.py collectstatic

这样frontend/dist/static里面的东西就到了项目根目录的static文件夹里面了。

那么为什么不直接手动把构建好的dist/static拷过来呢?因为开始提过Django自带的App:admin 也有一些静态文件(CSS,JS等),它会一并collect过来,毕竟Nginx只认项目跟目录的静态文件,它不知道Django把它自己的需求文件放到哪了。

开头说过Django配置灵活,那么我们专门为Django创建一个生产环境的配置:

prod.py

prod.py 与 默认 settings.py 同目录。

导入公共配置

from .settings import *

生产环境关闭DEBUG模式

DEBUG = False

生产环境开启跨域

CORS_ORIGIN_ALLOW_ALL = False

特别说明,下面这个配置不需要,因为前端是Vue.js构建的,它默认使用static作为静态文件入口,我们Nginx配置static为入口即可,保持一致,没Django什么事。

STATIC_URL = '/static/'

如何使用这个配置呢,进入 wisg.py 即uwsgi配置里面的module配置修改为:

import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "**inner_ulb_manager.prod**")
application = get_wsgi_application()

启动uwsgi

uwsgi --ini inner_ulb_manager.ini

启动ngingx

service nginx start

至此,部署就完成了。

10. 效果图

List 组件:

图片[4]-使用Django + Vue.js快速而优雅地构建前后端分离项目-JieYingAI捷鹰AI

传单个 ULB 对象给 Detail 组件使用即可Detail 组件:

图片[5]-使用Django + Vue.js快速而优雅地构建前后端分离项目-JieYingAI捷鹰AI

当然里面还实现了前面提到的 ULB 的 VServer 创建,VServer 的 RServer 的创建等。

作者介绍

图片[6]-使用Django + Vue.js快速而优雅地构建前后端分离项目-JieYingAI捷鹰AI

高远,3 年 DevOps 经验,UCloud 网络产品运维工具开发负责人,专注于小型团队项目的快速构建与开发,希望用软件工程的思想更优雅的改变世界。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
来说点什么吧!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容