社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Django

用 Vue3 和 Django 快速搭建前后端分离项目

Python编程时光 • 2 年前 • 557 次点击  

Web 开发中前后端分离已经是常规性做法,但是不少初学者不太熟悉如何前后端分离,搭建 Demo 的时候遇到的问题也比较多,今天就来分享一下如何用 Vue 和 Django 快速搭建前后端分离项目。

# 先搭建前端

这里使用 Vue3,可以参考官方文档[1]。

在终端或者命令窗口执行:

npm init vue@latest

这将后自动安装 Vue 的最新版本,并初始化一个 Vue 项目,填写一个项目名称,其它都直接回车按默认值处理即可:

然后执行这些,就会看到前端项目启动了:

cd front_end
npm install
npm run dev

 安装依赖

现在的前端项目,只会显示一个静态的网页,我们需要给它加点料,比如搞个表单,让它发起 get 或 post 请求,这样我们需要安装下面的依赖,在 front_end 目录下执行:

npm i element-plus -S
npm i axios -S
npm i mockjs -S

如果你用的是 Vue2,请安装 element-ui。

其中:

element-plus/element-ui 是 vue 的一个 ui 库,引入它主要为了使用一些好看的按钮,表单,文本框等,可以替换你喜欢的 ui 库,也可以不用。

axios 类似于 AJAX 的功能,主要为了访问后端 api 来获取数据。

mockjs 主要用于模拟后端的 api 接口返回数据。当前端工程师需要独立于后端并行开发时,后端接口还没有开发完成,那么前端怎么获取数据?这时可以考虑前端自己模拟假数据,mockjs 可用来生成随机数据,拦截 Ajax 请求。

 导入依赖

现在,让我们修改 main.js ,全局引入 element,并使用 mockjs 模拟接口数据

 import {
    createApp
from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import './assets/main.css'
import './mock'
const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

这里,有个 mock.js,我们还没有编写,等会写。

 编写一个 Demo 页面

在 front_end/src/components/ 下,编写一个 TestApi.vue 文件,内容如下:

<template>
  <el-form :inline="true" :model="formInline" size="small">
    <el-form-item label="用户信息">
      <el-input
        class="input"
        v-model="formInline.username"
        placeholder="用户名"
      >
el-input>
      <el-input
        class="input"
        v-model="formInline.email"
        placeholder="email"
      >
el-input>
    el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onSubmitGet">get 查询所有el-button>
      <el-button type="primary" @click="onSubmitPost">post 提交el-button>
    el-form-item>
    <el-input
      type ="textarea"
      :rows="6"
      placeholder="此处返回结果"
      v-model="results"
      class="textarea"
    >

    el-input>
  el-form>
template>
<script>
import axios from "axios";
export default {
  data() {
    return {
      formInline: {
        username"",
        email"",
      },
      results"",
    };
  },
  methods: {
    onSubmitGet() {
      console.log("submit! get");
      axios.get("api/users/")
      .then((res) => {
          this.results = JSON.stringify(res.data);
          console.log(res.data); //在console中看到数据
        })
        .catch((res) => {
          alert("wrong");
        });
    },
    onSubmitPost() {
      console.log("submit! post");
      axios.post("api/users/"this.formInline)
      .then((res) => {
         console.log(res.data); //在console中看到数据
        })
        .catch((res) => {
          alert("wrong");
        });
    },
  },
};
script>

<style scoped>
.input {
  width200px;
}
button {
  width100px;
}
.textarea {
  width900px;
}
style>

上面的页面有一个表单,可以发起 get 或 post 请求。

这个组件写完了,需要把它展示到页面上,修改 App.vue 把所有 TheWelcome 替换成 TestApi 就可以了。

现在可以编写 mock.js 了,在 front_end 目录下,新建 mock.js 文件,写入以下内容:

//引入mockjs
import Mock from 'mockjs'
// 获取 mock.Random 对象
const Random = Mock.Random;
//使用mockjs模拟数据
Mock.mock('api/users/', (req, res) => { //当post或get请求到/api/users/路由时Mock会拦截请求并返回上面的数据
    var list = [{
        "url""http://127.0.0.1:8000/users/3.json",
        "username""aaaaaa",
        "email""",
        "groups": []
    }, {
        "url""http://127.0.0.1:8000/users/2.json",
        "username""somenzz",
        "email""",
        "groups": []
    }, {
        "url""http://127.0.0.1:8000/users/1.json",
        "username""admin",
        "email""admin@example.com",
        "groups": []
    }]
    return list
})

现在,再运行一下 npm run dev,浏览器打开 “http://127.0.0.1:5173/”,点击 get 按钮,会发现 mock 已经生效。

前端 demo 已经差不多了。

接下来让我们看看后端工程师的任务。

# 再搭建后端

这里以 DRF(Django REST Framework) 为例。如果对 DRF 还是第一次接触,建议先按官方的教程[2]走一遍。

执行以下命令创建一个后端 Demo:

django-admin startproject rear_end
cd rear_end
django-admin startapp restapi
#这一步会创建管理员用户,请记录设置的密码
python manage.py createsuperuser --email admin@example.com --username admin

接下来在 settings.py 文件中增加 'rest_framework' 到 INSTALLED_APPS 列表即可

接下来执行以下命令启动 django 后端服务。

python manage.py runserver 

我们在浏览器中输入 http://127.0.0.1:8000/admin 然后输入管理员用户名和密码,再新增 3 个用户,可以随便填写,目的是为了多几条测试数据。

接下来访问 http://127.0.0.1:8000/user.json 可以看到返回如下 json 格式的数据。

后端开发工作至此告一段落。

# 前后端联调测试

开发环境下,vue 会占用一个端口,这里是 localhost:5173,而 djangorestframework 也会占用一个端口,比如 localhost:8000,那么 localhost:5137 需要获取 localhost:8000 的数据进行联调,因此我们将前端 demo 中  RestApi.vue 中请求的接口由 api/users 改为 http://127.0.0.1:8000/users.json,实际开发中通过配置文件来解决这个替换的问题。

实际执行的过程中,get 请求报错的结果如下:

Access to XMLHttpRequest at 'http://127.0.0.1:8000/users.json' from origin 'http://localhost:5137' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这里翻译成中文就是,跨域资源共享(CORS)策略阻止了从 localhost:5137 到 127.0.0.1:8000 的访问。那么什么是跨域资源共享 ,这里得解释下:

跨域资源共享的目的是共享,它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了 AJAX 只能同源使用的限制。显然,localhost:5137 到 localhost:8000 是不同源的,因此这里使用了跨域资源共享策略。但 CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。

整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。那么解决这个方法有两种:

第一种:设置服务器端,让它允许 localhost:5137 的跨域访问,上线后再改回来,为什么要改回来呢,因为要避免跨域攻击,详见知乎https://www.zhihu.com/question/26379635[3]。

第二种:将 127.0.0.1:8000 返回的 json 数据复制到 mock 的方式来联调。

看来第二种比较方便,前提是你需要学习如何使用 mock 来模拟后端 api。

为了在开发环境联调,我们将第一种方法进行到底,现在修改 django 的配置文件 settings.py 让它允许跨域。

1、安装 django-cors-headers

pip install django-cors-headers

2、修改 settings.py

INSTALLED_APPS = [
    ......
    'corsheaders',
    ......
]

MIDDLEWARE = [
    ......
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ......
]

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True

此时,执行 get 请求顺利完成。

这里,我们填写用户名和邮箱,提交 post 请求后,users 表会新增一条记录,通过 get 请求也可以查询出来,大家可以动手试一试。

实际开发中,我们在请求后端接口时的 url 一般不会填写 ip 地址和端口,而是 'api/xxx' 这种形式,这里是为了展示如何在开发环境进行前后端联调而写成此种形式。

# 上线部署

先执行 npm run build 来打包,默认配置上,将生成 dist 目录,并在 dist 目录下产生 index.html 文件,及静态资源 js,css,fonts,它们都在 dist 目录下。

这个 dist 目录就是需要我们上线部署的资源。

我到网上搜索了一下, 有两种主流方式,一种是直接将 dist 目录位置配置在 nginx 上,然后使用 nginx 反向代理 UWSGI 或 gunicorn,通常使用 socket 协议。

另外一种是将 dist 目录的资源由 django 驱动,这样就不涉及跨域的问题,但需要在打包时稍做调整。在 front_end 目录下新建 vue.config.js 文件,并添加以下内容:

module.exports = {
  // 选项...
  assetsDir : 'static'
}

再次执行 npm run build 我们会发现 js,css,fonts 都放在 static 目录下了,这样做的原因是:django 模板视图指定的 html 文件不能与静态资源放在同一路径下,至少有一个相对目录才可以。换句话说,django 配置文件中 STATIC_URL 默认为 '/static/' ,不允许设置为空,就是说,127.0.0.1:8000/static/js/xxx.js 才能正确的访问静态资源,但默认的 vue 默认配置生成的静态资源和 index.html 是同级的,因此需要稍微调整下才可以。

接下来修改下 django 的配置文件:

1、可以注释掉所有关于跨域的代码。参考前面的步骤 2、增加以下配置,让 django 在 debug 模式下能找到静态资源

STATICFILES_DIRS = [os.path.join(BASE_DIR, "dist/static")]

TEMPLATES = [
    {
        'BACKEND''django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'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',
            ],
        },
    },
]

修改 setting.py 同目录的 urls.py 加入模板视图,指定 index.html

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', TemplateView.as_view(template_name="index.html"), name='index'),
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

执行 python manage.py runserver 后打开浏览器,执行 get 请求,可以看到如下结果,此时前后端已经同源。

再接下来的配置基本和第一种方案一样了,设置 django 收集静态资源的路径 STATIC_ROOT,执行 python manage.py collectstatic ,然后参考下面 uwsgi 的配置进行生产环境部署,这种方法不需要后端允许跨源,比较安全。

生产环境上线,你需要了解一下 nginx 及 uwsgi。

nginx 可以指定首页 index.html,静态资源,端口转发,路由转发,负载均衡等等,网上有详细的配置说明,不再列举。uwsgi 也可以指定静态资源,主要用来驱动 django。这里贴一份我使用过的配置:

[uwsgi]
socket = :80
master = true
chdir = /home/aaron/web/django-mysite
wsgi-file = blogproject/wsgi.py
processes = 4
threads = 10
virtualenv = /home/aaron/pyenv
static-map = /static=/home/aaron/web/django-mysite/static
static-map = /media=/home/aaron/web/django-mysite/media
mime-file = /home/aaron/web/django-mysite/mime.types
disable-logging
logto = /home/aaron/web/django-mysite/uwsgi.log
#使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
daemonize = /home/aaron/web/django-mysite/uwsgi.log

# 最后的话

以上都是自己一点一点实践中的总结,希望对从事 Python 及 vue 的初学者有帮助,如果有问题可以发消息交流






Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/148592
 
557 次点击