【web系列十】Vue3+Django+MySQL搭建前后端框架

目录

写在前面

Vue3和Django通信

代码转移

代码转移

页面请求与显示

跨域请求

服务端发出的跨域请求

浏览器发出的跨域请求

csrf认证

前后端通信示例

django

vue3

演示

Django和MySQL通信

准备

安装插件

创建数据库

连接数据库

生成数据表

创建用户

另一种远程访问的方式

通信示例

vue工程

django工程

测试

参考资料


写在前面

        这篇文章主要介绍前端、后端和服务器间的通信,如果有对这三个部分还不了解的或者不知道怎么搭建工程的可以去看博主的这三篇文章,希望能对你有帮助。

Django 【web系列二】Django服务器搭建_Nicholson07的博客-CSDN博客_django 应用服务器

Vue 【web系列八】vscode下vue3+vue/cli+pinia+typescript搭建前端开发环境_Nicholson07的博客-CSDN博客

MySQL 【web系列九】快速上手MySQL数据库_Nicholson07的博客-CSDN博客

        另外,这里贴出一些官方文档,本文没有讲到的内容,大家可以从官方文档自行了解。

Django Django,Django中文网,Django中文社区,django教程,Django学习!

Vue Vue.js (vuejs.org)

MySQL MySQL :: MySQL Documentation

axios Axios 中文文档 | Axios 中文网 | Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js (axios-http.cn)

Vue3和Django通信

        对django单体web框架熟悉的朋友应该对前端(这里指html页面)与后端(django服务器)通信的过程比较了解了。那么现在用vue3+django前后端分离框架实现通信其实也不麻烦,关键问题只有三个:

  1. 代码转移:html及一些js/ts代码存放的位置从django转移到了vue3工程下。
  2. 跨域请求:原本只要处理服务器端的跨域请求,现在还得考虑浏览器发出的跨域昂问请求。
  3. csrf认证:django的csrf_token认证问题更加复杂。

代码转移

代码转移

         这个其实比较好理解,原本的django单体框架下,html页面一般就在django的templates下,现在直接转移到vue工程下的components下。

        django工程结构示例。

---hello               //项目容器
  |---hello            //主目录,整个项目的配置和调度中心。
  |  |---__init__.py   //告诉python,该目录是一个包   。  
  |  |---asgi.py       //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
  |  |---settings.py   //该 Django 项目的设置/配置。
  |  |---urls.py       //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
  |  |---wsgi.py       //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
  |---first_app            //新建的应用
  |  |---migrations    //用于数据库迁移,便于数据库管理
  |  |  |---__init__.py
  |  |---templates     //用于存放html文件,即网页结构
  |  |  |---hello.html //hello.html页面,打印hello world!
  |  |---__init__.py
  |  |---admin.py      //自带的后台管理
  |  |---apps.py       //创建对应app类的文件
  |  |---models.py     //mtv中的m,用于和数据库交互
  |  |---tests.py      //用于开发测试用例
  |  |---urls.py       //first_app的urls目录
  |  |---views.py      //mtv中的v,用于处理网页的后端业务逻辑
  |---db.sqlite3       //轻量级数据库,用于和models交互
  |---manage.py        //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。

         vue3工程结构示例。

|-dist                          -- 生成打包后文件
|-node_modules                  -- 项目依赖包的目录
|-public                        -- 项目公用文件
	|--favicon.ico              	-- 网站地址栏前面的小图标
	|--index.html                  -- 项目的默认首页,Vue的组件需要挂载到这个文件上
|-src                           -- 源文件目录,程序员主要工作的地方
	|-api                           -- 与后端交互使用相关方法和配置
	|-assets                   		-- 静态文件目录,图片图标、样式,比如网站logo
	|-components                	-- Vue3.x的自定义组件目录
	|-router                    	-- vue-router相关配置
	|--utils                    	-- 通用工具包
	|--views                    	-- 页面
	|--App.vue                  	-- 项目的根组件,单页应用都需要的
	|--main.css                	-- 一般项目的通用CSS样式写在这里,main.js引入
	|--main.js                  	-- 项目入口文件,SPA单页应用都需要入口文件
|--.gitignore                   -- git的管理配置文件,设置那些目录或文件不管理
|--package-lock.json           -- 项目包的锁定文件,用于防止包版本不一样导致的错误
|--package.json                -- 项目配置文件,包管理、项目名称、版本和命令

页面请求与显示

  1. 直接由vue发出axios请求,请求url直接鞋厂服务器端的域名+'/hello'
  2. 当通过了跨域请求和csrf认证后就会进入django的urls.py
  3. 根据axios请求的url找到views.py中的函数,要注意django返回直接使用JsonResponse或者HttpResponse就可以,不需要使用附带url的render了
  4. vue接收到django返回的内容后直接更新页面

跨域请求

服务端发出的跨域请求

  • 可以使用哪些iP或者域名来访问服务器
  • 默认为空,可以使用127.0.0.1或者localhost,也可以指定ip
  • 如果想允许任何ip进行访问,可以设置为*在项目下的settings.py中设置允许任何ip访问
ALLOWED_HOSTS = ['*']

浏览器发出的跨域请求

         这里需要用到一个第三方包django-cors-headers,

 1、安装

pip install django-cors-headers

2、配置settings.py文件 

INSTALLED_APPS = [

    ...

    'corsheaders',

    ...

]
MIDDLEWARE_CLASSES = (

    ...

    'corsheaders.middleware.CorsMiddleware', # 注意顺序,必须在CommonMiddleware之前

    'django.middleware.common.CommonMiddleware',
    ...

)
# 增加跨域忽略
CORS_ORIGIN_ALLOW_ALL = True
# 允许所有方法
CORS_ALLOW_METHODS = ('*')
# 允许所有请求头
CORS_ALLOW_HEADERS = ('*')
# 允许携带cookie
CORS_ALLOW_CREDENTIALS = True 

        当CORS_ORIGIN_ALLOW_ALL = True是允许所有域名访问,如果想更安全或者是更加有针对性一点的话,可以就添加白名单

CORS_ORIGIN_WHITELIST = (
    'localhost:8080',
)

         另外,请求方法也可以更有针对性

# 设置允许哪些请求方式进行跨域请求
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
    'VIEW',
)

csrf认证

        这个就比较麻烦了,这个机制时django为了防止跨域攻击制定的,浏览器初次访问html页面时,django会生成一个csrf_token发送给浏览器,浏览器将他记录到cookie中,之后做Post请求的时候需要将这个cookie发送给django,django会验证这个cookie与服务器中记录的csrf是否一致,只有保持一致时,才能执行之后的请求。

        之前使用django单体框架的时候,可以直接在html中去获取csrf_token,而当前后端分离后,vue生成的页面无法直接获取到django生成的csrf_token,博主查阅了网上好多资料,尝试了很多方法,暂时也没找到在启用了csrf_token机制后,实现vue3向django发送post请求通信的方法。

        不过有一个比较粗暴的方法,可以直接把setting.py中以下部分注释掉

django.middleware.csrf.CsrfViewMiddleware

前后端通信示例

        这里使用axios实现一个简单的前后端通信示例,直接上关键模块的代码。

django

views.py

from django.http import JsonResponse

def show_res(request):
    response = {}
    response['age'] = 18
    if request.method == 'POST':
        if len(request.POST['age']) > 0:
            response['age'] = request.POST.get['age']
    return JsonResponse(response)

vue3

hello.vue

<template>
    <div id='test'>
        <h1>姓名:{
   
   {name}}</h1>
        <h1>年龄:{
   
   {age}}</h1>
        <button @click='show_get'>get</button>
        <button @click='show_post'>post</button>
    </div>
</template>

<script>
import axios from 'axios'
import {ref} from 'vue'

export default {
    name: 'test',
    setup(){
        let name = ref('zhangsan')
        let age = ref('10')
        
        function show_get(){
            axios.get(
                '/show_res'
            ).then(response => {
                age.value = response.data['age']
                console.log(age.value)
            })
        }

        function show_post(){
            var form = new FormData();
            form.append('age', 24);
            
            axios.post(
                '/show_res',
                form
            ).then(response => {
                age.value = response.data['age']
                console.log(age.value)
            }).catch(error => {
                console.log(error)
            })
        }
    }
}
</script>

<style></style>

        细心的朋友可能注意到了,这里我在发送axios请求的时候,只写了部分url,这个怎么实现呢?其实也很简单,在main.js中配置一下axios的默认参数即可。

import { createApp } from 'vue'
import App from './App.vue'
import axios from 'axios'

createApp(App).mount('#app')

axios.defaults.baseURL = 'http://10.40.100.21:8020'

        这样的话,axios请求时,会默认以baseURL为基础做字符串拼接,生成完整的url。

演示

        现在开发已经完成了,咱们来试一下。

        可以看到一开始页面上显示的年龄时10,当点击了get按钮后会变成18,点击了post按钮后会变成24。

设置了baseURL后向其他url发请求

        建议建立一个临时axios实例,而不是更新默认的baseURL.

import axios from 'axios'

const axios_temp = axios.create({
    baseURL: "http://xx.xx.xx.xx:xxxx"
})

axios_temp.get("/xxxx")
.then((response) => {})
.catch((error) => {})

Django和MySQL通信

准备

安装插件

        安装python中操作MySQL的库,这里用了django官方推荐的mysqlclient

pip install mysqlclient

创建数据库

        使用mysqlclient无法创建数据库,只能和现有的数据库关联,因此首先要在MySQL中船舰好数据库。

        可以直接再mysql命令行中用create创建,也可以用类似SQLyog等可视化工具创建。

        这里创建了一个test数据库。

连接数据库

1、工程同名app下的settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'root',
        'PASSWORD': 'hirain123',
        'HOST': 'localhost',
        'PORT': '3306',
        'OPTION'; {
            'init_command': 'SET sql_model="STRICT_TRANS_TABLES"',
        }
    }
}

2、子应用的models.py

from django.db import models

class User(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)
    level = models.IntegerField(default=1)
    createTime = models.DateTimeField(null=True)

    class Meta:
        db_table = 'User'

3、子应用中的admin.py

        如果熟练使用Mysql或SQLyog这类可视化工具操作数据库的话,这步可以省略

from django.contrib import admin
from . import models

admin.site.register(models.User)

         这里不介绍如何使用admin管理数据库,想了解的可以看这篇文章。

(5条消息) django的admin组件使用详解_Dream_it_possible!的博客-CSDN博客_admin django

生成数据表

1、更新数据表变化情况

python manage.py makemigrations main_app

2、生成/更新数据表

python manage.py migrate

        这时就可以看到数据库中已经生成了对应的数据表了。

创建用户

        一般多人开发的项目,需要共用数据库,这时通常会把数据库放在公共服务器上,并且允许用户使用ip访问。

        首先要使用以下语句在数据表中创建一个用户名为name,密码为password,且ip为192.168.1.200的用户。

create user 'name'@'192.168.1.200' identified by 'password';

        使用grant语句赋予权限,想具体了解grant语句的话可以移步(3条消息) 【web系列九】快速上手MySQL数据库_Nicholson07的博客-CSDN博客

grant all privileges        // all privileges是赋予所有权限 
on *.*                      // 代表权限范围包括所有数据库中的所有数据表
to 'name'@'192.168.1.200'   // 用户名称和ip
with grant option;          // 赋予该用于给予他人权限的权限

注意,旧版的MySQL还支持使用以下语句实现在创建用户的同时赋予权限,新版(具体是哪个版本开始的不清楚)必须要分开实现。

grant all privileges on *.* to 'name'@'192.168.1.200' identified by 'password' with grant option;

         这样,在mysql库中的user表中就可以看到我们添加的用户啦。

         这样的话,用户name就可以在192.168.1.200的电脑上使用password登录我们的数据库了。

另外,建议多人开发时,为了相互之间不影响,可以在同一个公共机上的同一个端口下创建多个内容相同,单名称不同的数据库,每个人使用自己的,这样在修改了表结构或表数据时不会影响别人。 

另一种远程访问的方式

        将对应用户的Host改为%,我们拿root用户举例。

        将host改为%后,root用户就可以在任意ip下访问我们的数据库了。 

通信示例

vue工程

<template>
    <div id="test">
        姓名:<input type="text" name="name" v-model="user_name"> <br/>
        用户等级:<input type="number" name="level" v-model="level"> <br/>
        <button @click='add_user'>提交</button>
    </div>
</template>

<script setup>
import axios from 'axios'
import {ref} from 'vue'

let user_name = ref('')
let level = ref('')

function add_user() {
    var form = new FormData();
    form.append('name', user_name.value);
    form.append('level', level.value);
    axios.post(
        '/add_user',
        form
    )
}
</script>

django工程

from django.http import HttpResponse
from . import models

import datetime


def add_user(request):
    name = request.POST['name']
    level = request.POST['level']
    createTime = datetime.datetime.now()

    user = models.User.objects.create(name=name, level=level, createTime=createTime)

    context = {}
    context['msg'] = '用户新增成功'
    context['数据库中的id'] = user.id
    
    return HttpResponse(str(context))

测试

        初始的数据库 

         页面

        输入信息

        提交后的页面

         提交后的数据库

         这样就实现了django和数据库的通信,并以及使用vue操作数据库。

参考资料

【Django 2021年最新版教程8】操作Mysql数据库 mysqlclient安装和使用_软件工程小施同学 的技术博客_51CTO博客

(5条消息) django的admin组件使用详解_Dream_it_possible!的博客-CSDN博客_admin django

猜你喜欢

转载自blog.csdn.net/Nichlson/article/details/125602306