Django+Vue 项目记录

原文:个人主页原文

技术栈:Vue + Django + MySQL

IDE:Pycharm

本项目为2022秋北航网络空间安全学院数据库实验课程作业。作业需要进行简单的全栈开发。时间紧迫,且本人初次接触Vue,过程中遇到了许多问题。在此记录项目的开发过程。

项目GitHub仓库:https://github.com/yunsaijc/Autumn-DB_Lab3-Django-Vue-Project.git

后端-Django

初始化与配置

新建项目

通过命令django-admin startproject project_name来在当前路径下创建一个新的项目,项目文件夹结构如下:

随后通过命令python manage.py startapp app_name来创建一个app,并将该app的名字加入到项目文件夹的settings.py下:

INSTALLED_APPS = [
    ...
    'api'
]

在该app文件夹下创建一个urls.py用于管理url,文件夹目录结构如下:

连接数据库

在项目文件夹的settings.py下设置数据库信息:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'DB_Lab3',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'admin',
        'OPTIONS': {
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        }
    }
}

同时在项目文件夹的__init__.py下配置:

import pymysql
pymysql.install_as_MySQLdb()

然后运行命令python manage.py makemigrations生成迁移文件,再通过python manage.py migrate进行迁移,最后运行python manage.py inspectdb > users/models.py,这时候app文件夹下的models.py就会根据数据库中的表自动生成类。

跨站点请求设置

需要进行跨站点请求的相关设置。
首先通过pip安装django-cors-headers包,然后在settings.py下进行设置:

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

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

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True

具体实现

后端逻辑的实现在app文件夹的views.py文件中完成,在本项目中也就是/api/views.py。其中登录函数的代码如下所示,完整代码见Github仓库。

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        if username == '' or password == '':
            return JsonResponse({'errno': 2, 'msg': "用户名或密码为空"})
        try:
            user = Users.objects.get(user_name=username)
        except:
            return JsonResponse({'errno': 2, 'msg': "用户不存在"})
        if password == user.pass_word:
            return JsonResponse({'errno': 0, 'msg': "登录成功", 'username': username})
        return JsonResponse({'errno': 2, 'msg': "密码不正确"})
    return JsonResponse({'errno': 1, 'msg': "请求方法错误"})

前端-Vue

初始化

创建项目:vue create project_name,选择vuex(前端状态存储管理)和router(路由管理)

项目结构如下。其中src文件夹存放源代码,dist文件夹存放npm run build,命令编译后生成的文件:

src文件夹结构如下:

在这里插入图片描述

各个目录或文件的说明如下:

目录/文件说明
node_modulesnpm 加载的项目依赖模块
public静态资源,build 构建后为根目录,含网站导航栏图标、首页入口文件
src开发做的事情基本都在这个目录下,含: • assets: 放置一些图片、字体等资源 • components: 放置组件文件,一般为全局组件 • router: 网站路由跳转设置 • store: 前端数据存储 • views: 放置各页面文件 • App.vue: 项目入口文件 • main.js: 项目的核心文件,在这里可以导入各种全局依赖
.xxx文件配置文件,包括语法配置、git配置(.gitignore)等
package.json项目配置文件
README.md项目的说明文档

文件结构理解

  1. 入口的main.js文件引入vue框架和App.vue主组件,然后实例化vue对象,在components属性中定义组件名

  2. App.vue主组件,里面集合了html, js, css语法,分别对应vue文件的<template>, <script>, <style>部分。

    在此主组件文件中,也可以引用其他子组件,引用时在script标签所在的js中用import引入,然后在实例化vue对象中的components中定义名字,然后在template所在的html中运用

  3. 子组件在components文件中,一般此文件夹中放置的都是子组件,被App.vue主组件引用

具体实现

前端的实现在appfront文件夹的views文件夹中完成,在本项目中也就是/appfront/views。其中登录页面的代码如下所示,完整代码见Github仓库。

<template>
  <div id="login" class="login">
    <div class="wrap">
      <h1>登 录</h1>
      <h2 v-if="userInfo!=null">您已经以 {{userInfo.user.username}} 的身份登录</h2>
      <el-form ref="form" class="form">
        <el-form-item prop="username">
          <el-input placeholder="用户名" type="username" v-model="username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item id="password" prop="password">
          <el-input placeholder="密码" show-password type="password" v-model="password" autocomplete="off" @keyup.enter.native="login" ></el-input>
        </el-form-item>
        <div >
          <el-button type="primary" @click="click_login">登&nbsp;&nbsp;录</el-button>
          <el-button type="primary" @click="click_register">注&nbsp;&nbsp;册</el-button>
          <el-button v-if="userInfo!=null" type="danger" @click="click_logout">登&nbsp;&nbsp;出</el-button>
        </div>
      </el-form>
    </div>
  </div>
</template>

<script>
import qs from "qs";
import user from "@/store/user"
const userInfo = user.getters.getUser(user.state());
export default {
  name: "login",
  data() {
    return {
      userInfo,
      username: '',
      password: ''
    }
  },
  mounted: function() {
    this.username = userInfo.user.username
  },
  methods: {
    click_login() {
      this.$axios({
        method: 'post',
        url: '/api/login/', 
        data: qs.stringify({
          username: this.username,
          password: this.password
        })
      })
      .then(res => {
        switch (res.data.errno) {
          case 0:
            window.alert("登录成功!");
            /* 将后端返回的 user 信息使用 vuex 存储起来 */
            this.$store.dispatch('saveUserInfo', {
              user: {
                'username': res.data.username
              }
            });
            location.reload();
            break;
          default:
            window.alert("登录失败!" + res.data.msg);
            break;
        }
      })
      .catch(err => {
        console.log(err);         /* 若出现异常则在终端输出相关信息 */
      })
    },
    click_register() {
      this.$axios({
        method: 'post',
        url: '/api/register/',
        data: qs.stringify({
          username: this.username,
          password: this.password
        })
      })
      .then(res => {
        switch (res.data.errno) {
          case 0:
            window.alert("注册成功!");
            break;
          default:
            window.alert("注册失败!" + res.data.msg);
            break;
        }
      })
      .catch(err => {
        console.log(err);         /* 若出现异常则在终端输出相关信息 */
      })
    },
    click_logout() {
      this.$store.dispatch('clear');
      window.alert('登出成功!');
      location.reload();
    },
  }
}
</script>

<style scoped>
#login {
  font-family: 'Noto Serif SC', serif;
  margin-top: 60px;
}
#login >>> .el-input__inner {
  font-family: 'Noto Serif SC', serif;
}
#login .bgbox {
  display: block;
  opacity: 1;
  z-index: -3;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 1s,transform .25s,filter .25s;
  backface-visibility: hidden;
}
#login .logo {
  cursor: pointer;
  overflow: hidden;
  height: 150px;
}
#login .wrap {
  width: 300px;
  height: 315px;
  padding: 0 25px 0 25px;
  line-height: 40px;
  position: relative;
  display: inline-block;
  background-color: rgba(255, 255, 255, 0.85);
  border-radius: 20px;
}
#login .btn_login {
  margin-top: 25px;
  text-align: center;
}
#login .btn_login button{
  line-height: 10px;
  font-family: 'Noto Serif SC', serif;
  width: 70%;
  height: 38px;
}
#login .suffix {
  font-size:14px;
  line-height:10px;
  color:#999;
  cursor: pointer;
  float:right;
}
</style>

将Vue与Django绑定

在前端文件夹下运行命令npm run build进行编译

目前我们已经分别完成了Django后端和Vue前端工程的创建和编写,但实际上它们是运行在各自的服务器上。因此我们须要把Django的·TemplateView·指向我们刚才生成的前端dist文件。

/DB_Lab3/urls.py下进行如下设置:

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

/DB_Lab3/settings.py下进行如下设置:

TEMPLATES = [
    {
        ...,
        'DIRS': ['appfront/dist'],
        ...
    },
]

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

随后在项目根目录执行python manage.py runserver即可。

遇到的坑

在使用element-ui时,遇到el-table表格不显示的问题,卡了两个小时才找到原因…

原因:版本问题!!!

解决办法:重新装一个低版本的包!!!

npm uninstall element-ui
npm install element-ui@2.9.2 -S

参考

https://cloud.tencent.com/developer/article/1005607

http://t.zoukankan.com/smile-fanyin-p-11258300.html

https://blog.csdn.net/weixin_48282959/article/details/124126667

https://blog.csdn.net/m0_59023970/article/details/123427008

https://blog.csdn.net/yehaocheng520/article/details/117025938

https://blog.csdn.net/qq_41216743/article/details/104605524

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值