Django+VUE搭建网站


Because the author is familiar with python, so we choose the django and vue to build a website.

Preparations

Windows 11; Pycharm

Anaconda

To avoid the inconsistency between dependencies, we first create a new envs.

conda create --name django python=3.10
activate django
conda install -c conda-forge django

Set the environment variables.

Notice: If we have several envs, we should adjust the order of environment variables and place the environment we are executing in the first place.

Vue

If it has errors with

error: RPC failed; curl 28 OpenSSL SSL_read: Connection was reset, errno 10054

``fatal: expected flush after ref listing`

input:

git config --global http.sslVerify "false"

This operation will disable SSL certificate validation for HTTPS connections using Git.

Git clone a web project.

git clone https://github.com/PanJiaChen/vue-element-admin.git

Install dependencies.

cd vue-element-admin
npm install

Error:

npm ERR! code 128

npm ERR! An unknown git error occurred

npm ERR! command git --no-replace-objects ls-remote ssh://git@github.com/nhn/raphael.git

npm ERR! Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.

npm ERR! git@github.com: Permission denied (publickey).

npm ERR! fatal: Could not read from remote repository.

npm ERR!

npm ERR! Please make sure you have the correct access rights

npm ERR! and the repository exists.

npm ERR! A complete log of this run can be found in:

npm ERR! C:\Users\AlexLee\AppData\Local\npm-cache\_logs\2023-07-03T10_34_10_937Z-debug-0.log

git config --global url."https://".insteadOf ssh://git@

INFO Starting development server...
10% building 2/5 modules 3 active ...node_modules\babel-loader\lib\index.js!E:\Code\Vue\vue-element-admin\node_modules\eslint-loader\index.js??ref--13-0!E:\Code\Vue\vue-element-admin\src\main.jsError: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
at module.exports (E:\Code\Vue\vue-element-admin\node_modules\webpack\lib\util\createHash.js:135:53)
at NormalModule._initBuildHash (E:\Code\Vue\vue-element-admin\node_modules\webpack\lib\NormalModule.js:417:16)
at handleParseError (E:\Code\Vue\vue-element-admin\node_modules\webpack\lib\NormalModule.js:471:10)
at E:\Code\Vue\vue-element-admin\node_modules\webpack\lib\NormalModule.js:503:5
at E:\Code\Vue\vue-element-admin\node_modules\webpack\lib\NormalModule.js:358:12
at E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:373:3
at iterateNormalLoaders (E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:214:10)
at iterateNormalLoaders (E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:221:10)
at E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:236:3
at runSyncOrAsync (E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:130:11)
at iterateNormalLoaders (E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:232:2)
at Array.<anonymous> (E:\Code\Vue\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:205:4)
at Storage.finished (E:\Code\Vue\vue-element-admin\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:55:16)
at E:\Code\Vue\vue-element-admin\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:91:9
node:internal/crypto/hash:71
at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}

Node.js v18.12.1

The reason is due to version incompatibility.

set NODE_OPTIONS=--openssl-legacy-provider

If this code can’t solve the problem, reduce the Node.js version to 16.

Vue基本结构

├── build                      // 构建相关  
├── config                     // 配置相关
├── src                        // 源代码
│   ├── api                    // 所有请求
│   ├── assets                 // 主题 字体等静态资源
│   ├── components             // 全局公用组件
│   ├── directive              // 全局指令
│   ├── filtres                // 全局 filter
│   ├── icons                  // 项目所有 svg icons
│   ├── lang                   // 国际化 language
│   ├── mock                   // 项目mock 模拟数据
│   ├── router                 // 路由
│   ├── store                  // 全局 store管理
│   ├── styles                 // 全局样式
│   ├── utils                  // 全局公用方法
│   ├── vendor                 // 公用vendor
│   ├── views                   // view
│   ├── App.vue                // 入口页面
│   ├── main.js                // 入口 加载组件 初始化等
│   └── permission.js          // 权限管理
├── static                     // 第三方不打包资源
│   └── Tinymce                // 富文本
├── .babelrc                   // babel-loader 配置
├── eslintrc.js                // eslint 配置项
├── .gitignore                 // git 忽略项
├── favicon.ico                // favicon图标
├── index.html                 // html模板
└── package.json               // package.json

Django

Open the Pycharm and choose “file – new project – django”.

Set the interpreter and application name.

├── app01
│ ├── __init__.py
│ ├── admin.py [fixed] django默认提供了admin后台管理。
│ ├── apps.py [fixed] app start class
│ ├── migrations [fixed] 数据库变更记录
│ ├── __init__.py
│ ├── models.py [important] 对数据库操作。
│ ├── tests.py [fixed] unit test
│ └── views.py [important] function。
├── manage.py
└── mysite2
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py 【URL->function】
└── wsgi.py

当执行 python manage.py migrate 操作时, 报错 (1051, “Unknown table ‘xxx’”), 这时数据库中是没有 ‘xxx’ 这个表的

解决:

先将 models.py 中你更新失败的表给注释掉

注释掉后执行

python manage.py makemigrations
python manage.py migrate --fake

上面执行成功后再将 models.py 中的表注释取消

取消注释后执行

python manage.py makemigrations
python manage.py migrate

当定义一个函数后,不加括号取函数名,表示仅获取函数对象本身,不会执行函数内部的代码:

pythonCopy codedef foo():
  print("foo")
  
func = foo # 仅获取函数对象,不会执行print语句

当需要调用这个函数时,需要加上括号,这样才会真正执行函数内部的代码

JS中的同步与异步

appendChild方法是在最后面进行添加,添加方法是同步,但是会造成加载顺序的问题,解决方法如下:

回调处理

el1.appendChild(div1, () => {
  el1.appendChild(div2, () => {
    el1.appendChild(div3)  
  })
})

一次性

const elements = [div1, div2, div3]
el1.append(...elements)

DocumentFragment 优化

const fragment = new DocumentFragment()
fragment.appendChild(div1)
fragment.appendChild(div2)
fragment.appendChild(div3)

el1.appendChild(fragment)

同步调用

function syncAppendChild(element) {
  // 1. 移出文档流
  element.remove(); 
  // 2. 同步执行插入,null就是在最后一个插入,否则在第二个变量前面插入
  document.body.insertBefore(element, null);
  // 3. 强制渲染
  document.body.offsetWidth; 
}

document.body.appendChild = (element) => {
  syncAppendChild(element)
}

总结:

appendchild 同步

innerHTML = ‘’ 同步

remove() 异步

DRF中对序列化数据进行分页

class AllUserView(ListAPIView):
    queryset = Users.objects.all()
    serializer_class = UserSerializer
    # 后端会自动处理 page 参数并返回相应页码的数据,前端只需要发送page是第几页即可
    pagination_class = UsersPagination

    def get(self, request, *args, **kwargs):
        # 获取经过分页的查询结果
        # filter_queryset会根据request来自己去看有什么要求从而进行数据过滤
        # self.get_queryset() 在默认情况下返回的就是视图类中的 queryset 属性的值
        queryset = self.filter_queryset(self.get_queryset())
        # 不让个人信息显示在他人信息里
        current_name = request.session.get('current_name', None)  # 获取当前用户名
        if current_name:
            # 过滤掉特定用户名的行
            queryset = queryset.exclude(userName=current_name)
        queryset = queryset.order_by('userName')  # 以 userName 列进行升序排序
        # 分页并返回分页后的结果
        page = self.paginate_queryset(queryset)

        if page is not None: # 有分页数据
            # 序列化self.get_serializer返回serializer_class
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data) # Json数据

        serializer = self.get_serializer(queryset, many=True)
        return JsonResponse(serializer.data)

对应前端JS代码:

fetch('/api/get_allusers/?page=' + pageToRetrieve)  
    .then(response => response.json())
    .then(allusers => {...

Fetch和Axios对比

import axios from 'axios';

// 创建 Axios 实例
const axiosInstance = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com', // 示例API
  timeout: 5000,
});

// 发起 GET 请求
axiosInstance.get('/posts/1')
  .then(response => {
    // 成功响应处理
    console.log('Axios Response:', response.data);
  })
  .catch(error => {
    // 错误处理
    console.error('Axios Error:', error);
  });
// 默认发起 GET 请求
fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    // 检查是否成功
    if (!response.ok) {
      throw new Error('Fetch Error: ' + response.statusText);
    }
    // 解析 JSON 响应
    return response.json();
  })
  .then(data => {
    // 成功响应处理
    console.log('Fetch Response:', data);
  })
  .catch(error => {
    // 错误处理
    console.error('Fetch Error:', error);
  });

添加拦截器

fetch本身没有自带的拦截器,需要手动额外添加

这里展示axios的用法

import axios from 'axios'
import { Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 5000 // 请求超时时间
})

// request拦截器
service.interceptors.request.use(config => {
  // Do something before request is sent
  if (store.getters.token) {
    config.headers['X-Token'] = getToken() // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
  }
  return config
}, error => {
  // Do something with request error
  console.log(error) // for debug
  Promise.reject(error)
})

// respone拦截器
service.interceptors.response.use(
  response => response,
  /**
  * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
  * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
  */
  //  const res = response.data;
  //     if (res.code !== 20000) {
  //       Message({
  //         message: res.message,
  //         type: 'error',
  //         duration: 5 * 1000
  //       });
  //       // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
  //       if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
  //         MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
  //           confirmButtonText: '重新登录',
  //           cancelButtonText: '取消',
  //           type: 'warning'
  //         }).then(() => {
  //           store.dispatch('FedLogOut').then(() => {
  //             location.reload();// 为了重新实例化vue-router对象 避免bug
  //           });
  //         })
  //       }
  //       return Promise.reject('error');
  //     } else {
  //       return response.data;
  //     }
  error => {
    console.log('err' + error)// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  })

export default service
import request from '@/utils/request'

//使用
export function getInfo(params) {
  return request({
    url: '/user/info',
    method: 'get',
    params
  });
}

文章作者: Alex Lee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alex Lee !
评论
  目录