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
});
}