跳到主要内容

主题更换和迁移到vercel记录

· 阅读需 4 分钟

首先是主题更换。之前用的主题原生很多动画和功能,但是我本身是不喜欢复杂的,所以把背景和功能改的很精简。但是这样反而做的不称心。我的理想样式是:文章居中,两侧没有除了目录外的任何东西。所以,我找到了目前用的这个 orange 主题,这次我用的时间打算长些,短时间不换了。

其次是静态网站服务器从 github-pages 转移到 vercel。主要考虑是,github-pages 要求对应的仓库必须是公开的,这样有心人可以看到每一次过往文章提交修改记录,这让我觉得有点膈应。vercel 是一种流行的无服务平台,代码托管在 github 仓库后,vercel 可以实现自动部署和发布。现在的工作流是,本地修改好文章,直接推到 github 私有仓库,vercel 检测到变化,自动部署。值得一提的是,我顺便更换了 DNS 的 nameserver,由原来 namesilo 默认的,换到全球最大的 CDN 商 cloudflare。中间的过程记录一下。

vercel 创建实例成功后,会分配一个 example.vercel.app的二级域名。为了将买到的域名用上,需要去自定义设置,添加域名,vercel 会给你一个 A 或者 CNAME 记录。如果是一级域名,给 A 记录;如果是二级域名,给 CNAME 记录。这时候要在 cloudflare 添加记录。首先注册 cloudflare,然后,输入自己先前购买的域名,自动导入目前的 DNS 解析记录和 nameserver。这时候,将 DNS 解析规则先删除,并来到 namesilo 的管理页面,改变 nameserver 为 cloudflare 提供的地址。到这里的修改都是实时生效的。回到 cloudflare,刷新,cloudflare 开始接管你的域名,这一过程会花费十几分钟。

然后,将之前 vercel 提供的解析记录,提供给 cloudflare。不同于 github-pages,只有输入一条就能解析了。

其中,名称就是二级域名,内容是 vercel 的地址。成功后,这是你浏览器发出的请求就会被 cloudflare 所解析啦,并且可以勾选他们家提供的 CDN 服务。据说,中国大陆的 cloudflare CDN 反而是减速器,所以我没选。设置好后,实测不用翻墙就可以访问网站。

以后就专心写文章啦!

latex奇怪bug解决方案

· 阅读需 4 分钟

用 overleaf 写大论文时候,有一个作者的名字带生僻字:“赟”,overleaf 会显示为“F”。解决方案如下:

在 usepackage 区里,添加以下代码:

\usepackage{ctex}
\setCJKfamilyfont{myfont}{BabelStone Han}
\newcommand{\MyFont}{\CJKfamily{myfont}}

意思是添加一个自定义指令,专门用某个可以正常显示生僻字的字体,这里是 BabelStone Han。

然后在正文处:

{\MyFont{赟}}

就可以正常显示了!

latex 清除浮动来消除大片空白

问题描述

虽然 latex 是自动排版,但是偶尔会出现明明可以放下内容的地方,被留下空白。通常是发生在多个表格或者图片相连,然后后面跟着文字,文字和最后一个图表之间就会分页。

解决方案

最简单的,先从垂直间距开始调起。\vspace{-1cm}。但是可能不起效果,比如本文提到的情景。

或者是清除浮动。浮动的含义是,图表的位置并不固定在源码的位置,而可能被放置在上下几页,具体取决于 latex 算法认为美观的地方。在我这种情况中,显然是 latex 的算法自动排列的算法不符合真正的美观,所以要手动取消浮动,并且人工微调。取消浮动的方式是引入下列的包:

\usepackage[section]{placeins} 避免浮动体跨过 \section
\usepackage{float} 禁止浮动
% ...
\begin{figure}[H]
% ...
\begin{table}[H]
% ...

幸运的是,取消浮动后,一张表占据一整页的现象消失了,而且位置刚好,没有出现大面积空白。

参考: https://www.zhihu.com/question/25082703

tabularx 解决表格满宽

需求:让表格宽度等于页面宽度,单元格列宽可以指定,单元格文字居中。

解决方案:tabularx 是 tabular 的增强版,可以指定表格总体所占宽度,设置步骤如下:

  1. 在导言区导入 tabularx 包,并设置自适应宽度和指定宽度两种列选项,使得文字可以居中(默认是左对齐)
\usepackage{tabularx}
\usepackage{array}
\usepackage{ragged2e}
% 该命令用于控制 p{} 的情况
\newcolumntype{P}[1]{>{\RaggedRight\hspace{0pt}}p{#1}} % 使用过程中,将p{4cm}换成P{4cm},小写改成大写即可!
% 该命令用于控制 X 的情况
\newcolumntype{Z}{>{\centering\let\newline\\\arraybackslash\hspace{0pt}}X} % 使用过程中,将Z 换成 X,即可!
\let\oldtabularx\tabularx
\renewcommand{\tabularx}{\zihao{5}\oldtabularx}

% 可利用 RaggedLeft Centering替换RaggedRight,实现靠右和居中 [代码对大小写敏感!!!!!!!!!!!!!!!!!!!!!!!!!!!!]

其中,p 表示指定宽度,X 表示自适应,也就是均分宽度。

  1. 在表格区域内使用方式:
\begin{table}[h!]
\centering
\caption{DICM、LIME、MEF、NPE数据集上的平均NIQE值} \label{dwtqrcp_niqe}
\begin{tabularx}{\textwidth}{ZZZZZ}
data
\end{tabularx}
\end{table}

\begin{tabularx}{\textwidth}{ZZZZZ} 第二个选项指定整体宽度,第三个是列选项。

站在更高的角度思考前后端分离

· 阅读需 5 分钟

似乎从我开始学编程起,默认的开发模式就是前后端分离。但是,面对一门心仪的后端框架(如 django,laravel,它往往还带着仿佛上古时期留下来的模板引擎。为什么随着时代的更迭,模板引擎这种明显前后端耦合的东西还会存在呢?面对自己将来的定位(独立开发者),该如何根据情况进行技术选型呢?

开门见山

直接说结论,碰到以下需求的,用前后端分离:

  • 你不是一个人单干,需要一个技术团队。也许这时候你的业务已经初具规模,那么,为了团队更顺畅的沟通,必然选择为团队协作开发而生的前后端分离。
  • 你的应用有多端需求,比如 pc/ios/android 都有页面要做,这样后端只需提供接口,各端负责展示,后端就实现了复用。
  • 你的产品确定了一上线肯定会有很多用户使用,有服务器压力。前后端分离可以方便的进行服务资源扩展。

从历史发展的角度

上古时期,前后端不分离,后端也要负责页面的展示。jsp、php 是最受欢迎的模板语言,因为他们可以很容易地搭建起网站。后来,移动互联网的到来才是改变一切的原因。一方面,移动互联网使得互联网用户井喷式增长,对于服务器的压力承受水平提出更高的要求,服务端渲染的模式在高并发场景下很容易导致宕机,造成损失;另一方面;移动端的原生应用肯定不是用服务器返回的 html 页面来展示的,它们都有各自的底层框架,这样,就必须将前后端解耦,使手机 app 能单纯获取到数据。

近年来,前后端分离的模式也在演进。主要是前端的变化:从 jquery 按页面开发,到 vue/react 框架按组件开发。前端的进化带来了新的问题:首屏加载速度慢和 seo 糟糕。

  • 首屏加载速度慢:前端项目用框架开发好后,打包生成的文件里,除了静态的 css、img、font,只有一个巨大的 js 文件夹和 index.html。如果没有优化,所有的资源文件一次下载完毕后才能正常显示,不过这种情况下,后续的页面跳转会比不用框架快。
  • seo 糟糕:中国的搜索引擎百度还不能解析 js 文件,只能爬取到空的 index.html 页面。

解决方案有很多,可以参考这篇文章(链接)。这里以 Vue 的 SSR 框架 Nuxt.js 举例。在服务端起一个 node 应用,浏览器到来时,先拦截执行部分 js 异步请求,提前将数据填充到 html 页面中返回浏览器。这样爬虫抓取到的页面就是带数据的,有利于 SEO。也就是说,nodejs 作为中间层,模拟了一部分浏览器渲染数据的角色。

总结

如果将来自己独立开发,如果有一个新的 idea,你想快速发布原型,查看市场反应,而且暂时没有手机原生 app 端的需要(手机可以在浏览器上访问,只要兼顾到响应式)。那么就用 laravel 框架的模板语言将产品快速做出来,如果将来业务量增长了,可以先分离前后端,前端用 SSR 框架重写,如果用户增长到一定规模,就招人,用高性能语言,如 java、go。

namesilo购买域名和github pages配置

· 阅读需 2 分钟

自从建立网站以来,每次访问,都困扰于输入长长的域名前缀 www,此外,goldspot 似乎也太长且拗口。坑爹的是,goldspot 绑定的 namesilo 账号不知为什么登不上去了。索性重开新号,购买新域名。

购买域名的过程不再赘述,这次花了人民币 16.90 元。为了将买到的 rula.life 和 li199-code.github.io 绑定,需要如下操作:

首先,在 github 的仓库设置里,输入 custom domain 并保存。注意要带上 www。然后将 hexo 本地博客源文件夹的 source 文件夹下的 CNAME 记录修改如下:

rula.life

不带 http 和 www。最后,在 namesilo 的 DNS 设置界面,选择 github 模板,一键应用。回到 github pages,设置 enforce https,完毕!

注意:在 pages 设置界面,DNS 检查时,要出现如下显示,才说明 CNAME 和 Namesilo 设置成功:

TLS

javascript 模块机制

· 阅读需 5 分钟

前言

最近阅读《深入浅出 nodejs》和《nodejs 实战》的时候,都把模块系统放在前面的位置介绍,可见其重要性。模块机制帮助开发者将代码分割成独立的、功能明确的块,可以单独开发、测试和维护。因为之前写的文章逻辑比较混乱,故重新写一下。

JavaScript 主要有以下几种模块机制:

  • ES6 模块 (ES Modules)
  • CommonJS 模块
  • AMD 模块
  • UMD 模块

其中,最常见的莫过于前两种。

ES Modules

这是在 ES6(ECMAScript 2015)中引入的标准模块系统。ES6 模块通过 import 和 export 关键字来导入和导出模块。ES6 模块具有以下特点:

  • 静态结构:模块的依赖关系在编译时就能确定,不需要在运行时解析。这使得工具可以进行静态分析和优化。(这是不是基于 Nodejs 的后端代码也要采用 ES6 模块机制的原因?)
  • 文件即模块:每个文件被视为一个独立的模块。
  • 默认导出和命名导出:可以导出多个命名导出,也可以有一个默认导出。从格式来看,采用命名导出时,导入文件中,模块名外带花括号,而默认导出则相反。
  • 多入口加载,结合第一点,因而可以实现按需加载。

示例:

导出模块 (math.js)

// Named exports
export function add(a, b) {
return a + b;
}

export const PI = 3.14159;

// Default export
export default function subtract(a, b) {
return a - b;
}

导入模块 (main.js)

// Importing named exports
import { add, PI } from "./math.js";

console.log(add(2, 3)); // 5
console.log(PI); // 3.14159

// Importing the default export
import subtract from "./math.js";

console.log(subtract(5, 2)); // 3

注意事项:

  • 模块路径:相对路径或绝对路径需要明确指定。
  • 顶级作用域:ES6 模块在模块顶级作用域中运行,因此每个模块都有自己的独立作用域。

CommonJS

CommonJS 模块是 Node.js 使用的模块系统,通过 require 导入模块和 module.exports 导出模块。CommonJS 模块具有以下特点:

  • 动态加载:模块在运行时加载,require 是一个同步操作。
  • 整个模块导出:可以导出一个对象,该对象包含多个属性和方法。
  • 单一出口:模块通过 module.exports 导出单一对象。

示例:

导出模块 (math.js)

function add(a, b) {
return a + b;
}

const PI = 3.14159;

function subtract(a, b) {
return a - b;
}

module.exports = {
add,
PI,
subtract,
};

导入模块 (main.js)

const math = require("./math");

console.log(math.add(2, 3)); // 5
console.log(math.PI); // 3.14159
console.log(math.subtract(5, 2)); // 3

注意事项:

  • 动态加载:模块在代码执行到 require 语句时才会加载。
  • 缓存:一旦模块加载,它会被缓存,再次 require 相同模块时将返回缓存的版本。

比较 ES6 模块和 CommonJS 模块

特性ES6 模块CommonJS 模块
语法import / exportrequire / module.exports
加载方式静态加载动态加载
依赖关系编译时确定运行时确定
顶级作用域模块级作用域文件级作用域
是否支持浏览器否(需要打包工具,如 Browserify)
缓存机制浏览器端和服务器端缓存均支持服务器端缓存
默认导出支持需要手动指定

Docker入门

· 阅读需 4 分钟

公司的项目是用 docker 来部署的。之前看过一个 docker 科普视频,还没有动手实践过。现在将查到的东西做一个梳理(windows 平台)。

docker 把一个应用的代码文件和依赖的环境打包进一个容器,并且这个容器可以极其方便地部署在不同的机器上。docker 有以下三个主要文件:

  • DockerFile 描述了如何创建 image 文件及其基本信息
  • image 文件 环境的完整信息,类似于 windows 安装时的 iso 文件,便携,可以发布到公共空间供他人下载。
  • container 容器,本机系统上的一个进程,将自身与外部操作系统隔离。

docker 使用方式

让我们从 DockerFile 开始。首先编写 dockerignore 文件,忽视某些文件和文件夹,使之不要打包进 image 文件。是不是很类似于 gitignore?是的,image 文件就可类比 git 工作区,可以提交到 dockerhub,一个 image 文件托管平台。然后,编写 DockerFile。它无后缀,可以像下面这样写:

FROM node:8.4
COPY . /app
WORKDIR /app
RUN npm install --register=https://register.npm.taobao.com
EXPOSE 3000

注意,RUN npm install 是在制作 image 文件阶段执行的,说明 npm 包会打包进 image 文件。

有了 DockerFile,就可以创建 image 文件。

docker build -t koa-demo .

-t指定 image 文件的别名,不然就是一串哈希字符。注意最后有一个点,表示 dockerfile 就在当前路径。运行后,新生成的 image 文件存在 windows 下的 C:\Users\${用户名}\AppData\Local\Docker\wsl\data\ext4.vhdx. 但是,要看是否创建成功,指令 docker image ls。

有了 image 文件,可以正式创建容器:

docker run -dp 8000:3000 koa-demo

-d detached, 单独模式,在后台运行。-p建立本机和容器端口之间的映射,即本机的 8000 映射到容器的 3000。koa-demo就是容器的别名。

补充:Docker 中的数据卷(Volume)是用来持久化容器中的数据的一种机制。数据卷可以在容器之间共享数据,并且可以保持数据的持久性,即使容器被删除或重新创建,数据仍然会保留。

docker volume create my_volume
docker run -d --name my_container -v my_volume:/path/to/mount my_image

终止容器,首先运行 docker ps,获得 容器名称或 id,运行 docker stop [name]。删除容器:docker rm [name]

docker compose

compose 是一个 docker 系统的工具,可以一次管理多个容器,并且替代了 bash 脚本,而使用 yaml 来启动容器。在 linux 中,它需要单独安装:

curl -L https://github.com/docker/compose/releases/download/1.3.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

# 验证安装
docker-compose --version

常用命令:

docker-compose up:启动应用,并创建、启动所有定义的服务容器。如果服务不存在,会先构建镜像。可以通过 -d 选项使应用在后台运行。 docker-compose down:停止并删除应用的所有容器、网络、存储卷等相关资源。 docker-compose start:启动应用的所有容器,但不重新创建。 docker-compose stop:停止应用的所有容器,但不删除。 docker-compose restart:重启应用的所有容器。

git、github及其在vscode中的状态表示

· 阅读需 8 分钟

前言

实习过程中,大量使用 git。放假前,同事提出,我提交的版本覆盖了他的。为了能在节后解决问题,顺便对 git 工具体系做一个彻底的复习,写下此文。

初始化

git 是一种分布式管理工具。它能实现多人共同维护一个工程文件。下载好 git,并配置好身份信息后,可以有两种方式开始 git: 一种是下载 git 仓库,一种是在本地执行 git init 。这两种方式执行后,文件夹里都会有一个 .git 文件夹。

git config 相关命令配置仓库,这篇文章介绍得很详细了。总体来说,git 配置分为三个层次:仓库级(local)、用户级(global)、系统级(system)。配置的优先级是仓库->用户->系统。git config -l可以将当前仓库的所有可用配置列举出来,如下:

diff.astextplain.textconv=astextplain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
http.sslbackend=openssl
http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
core.autocrlf=true
core.fscache=true
core.symlinks=false
pull.rebase=false
credential.helper=manager-core
credential.https://dev.azure.com.usehttppath=true
init.defaultbranch=master
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
user.name=li199-code
user.email=
http.sslverify=false
credential.http://git.zhi-shan.cn.provider=generic
credential.https://gitee.com.provider=generic
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.symlinks=false
core.ignorecase=true
remote.origin.url=http..
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
user.name=
user.email=

我现在有一个需求,要修改提交时的姓名和邮件:

git config --local --add user.name jason
git config --local --add user.email [email protected]

git 提交

可以理解有两种提交:一种提交到本地的 git 区,一种是在本地提交后,提交到远程仓库,即 push。

git status查看本地有哪些修改。git log查看提交日志。git checkout [hashcode]根据某次提交的哈希值将代码回滚。

有一个有用的 git log 命令:git log --graph --oneline. 可以用查看历史提交的记录。

branch 分支(时间线)

git branch [name]创建分支。新分支会继承主分支上的所有历史改动,类似于时间线的概念。

一般来说,其他分支是在主分支基础上的重大更新,如果要合并其他分支,需要在切换到主分支后,执行 git merge [name].

git checkout

git checkout [id] filepath 用于回滚时,最好加上要回滚的文件名,这样只会改变该文件,而不会专门进入 detached head 模式。

"Detached HEAD"是一个 Git 术语,用来描述 HEAD 指针在一个特定的提交版本上,而不是指向任何分支的状态。这种状态下,你处于一个游离的、临时的工作环境,没有与之关联的分支。

当你切换到一个特定的提交版本(通过提交哈希、标签或分支名)而不是一个分支时,Git 会将 HEAD 指针直接指向该提交。这就是所谓的"Detached HEAD"状态。

Detached HEAD 状态通常用于以下情况:

查看历史提交:你可以在 Detached HEAD 状态下查看、比较和分析以前的提交。这对于浏览代码历史、调试问题或查找特定更改非常有用。

临时工作:如果你想在不影响当前分支的情况下进行一些临时的更改或实验,可以切换到 Detached HEAD 状态。你可以在该状态下创建新的提交,但这些提交不会属于任何分支。

git remote

以上说的操作都是在本地完成的。如何将本地改好的代码,传到云端完成多人协同开发呢?

如果是本地初始化 git,在 git push 之前,需要配置文章仓库的 url:

git remote add <name> <url>

<name>是 url 的别名,毕竟 url 很长。默认为 origin。同时,本地 git 文件夹里的 ref 下,也会创建 origin 文件夹,存缓存数据。

git push origin master

vscode git 工作流

首先,正确的工作流是:add -> commit -> pull -> push。在 vscode 中,commit -> pull -> push 简化为一个按钮:commit & sync.

git 状态(更新)

16872235086311687223508501.png

这张图展示了 git 的四种状态:untracked, unmodified, modified, staged. 从指向每个状态的箭头,我解读出一些有用的信息。首先,git init命令执行,创建了一个“容器”,但是所有的文件依旧是 untracked. staged 要么是从 untracked 转来,要么是已经被跟踪的文件被修改后执行git add而来。stage 状态的文件被 commit 后,状态就会回到 unmodified。

在现代的工作环境下,大多数人是通过 vscode 等 IDE 进行 git 操作了。所以,结合 vscode 页面说明对应的 git 状态和操作有助于加深理解。以我的 vscode 界面为例。如果一个项目还没有被 git 管理,这时候初始化,那么在 vscode 的 explorer 里,所有文件都会变成绿色,这种对应的就是上图的 untracked 状态,绿色的 U。同理新建一个文件,也是这种状态。然后,如果修改了一个文件,modified,黄色的 M。删除不在上面的图中,表示为红色的 D。当然了,没有修改的文件就是白色的,unmodified。

17031659366861703165935807.png

继续看,只有处在 staged 状态的文件才能被 commit。所以下图的加号就是把 modified 变为 staged,点了之后,文件会进入 staged changes。这里都是为了精细化控制单个文件。另外,vscode 有自己一套默认规则。正常情况下,点 commit 按钮只会提交 staged changes 内容,如果只有 changes 没有 staged changes,那么 vscode 就会自动将 changes 内容变为 staged 并提交。

17031663916541703166390710.png

17031665366531703166535845.png

其他问题

为什么实习连的公司内部 gitlab 仓库,不用像 github 那样配置 ssh?

因为 git 远程仓库有两种方式,ssh 登录和 https 登录,而我是通过输入账号密码登录的,属于后者。且 windows credential helper 帮我记下了 git 仓库的账号和密码(一台主机可以储存多种仓库的账号,比如 github,gitlab),避免每次提交代码需要重复输入。

git 学习资源

可视化学习

Django ORM记录

· 阅读需 3 分钟

记录曾经不懂的问题和踩过的坑

choices

Django 模型中的字段有个 choices 属性,这个属性可以提供被选数据。如果一个字段设置了这个属性,在模版中如果我要显示这个字段,那么 django 模版系统就会将它默认解析为一个下拉菜单。

# models.py
choices = (
(1, '男'), (2, '女'), (3, '其他')
)
gender = models.IntegerField(choices=choices)
# html {{ obj.get_gender_display }}
##在模板中,为了获取元组中id对应值,用左边的语法

外键

#model.py

## 外键要关联的表
class department(models.Model):
name = models.CharField(max_length=32)

## 在结合modelForm时,若for循环输出,下面语句可避免bug
def __str__(self):
return self.name


department = models.ForeignKey(to='department', on_delete=models.CASCADE)
## 外键关联上后,执行迁移,会在本表创建一个名为'department_id'字段。
# html {{ obj.department.name }} ##department字段会返回一个department表的对象

modelForm

添加数据

当想让用户向已有数据库中添加新的数据,应该用 modelForm 来创建一个对象。这个对象可以用 for 循环来在模板中显示字段,而且具有自动对数据进行校验和报错功能。

## views.py

class employModelForm(forms.ModelForm):
## 默认校验非空,可以对数据进行个性化校验,如:
## password = forms.CharField(min_length=3, label='密码')
class Meta:
model = employee
fields = "__all__"

def add(req):
if req.method == 'GET':
# form = employeeForm()
form = employModelForm()
return render(req, 'emp_add.html', {'form': form})

form = employModelForm(data=req.POST)
if form.is_valid():
form.save()
return redirect('/emp/list/')

## 数据校验失败,将已输入的信息和产生的错误提示返回给页面
return render(req, 'emp_add.html', {'form': form})
{{field.label}}: {{ field }} {{ field.errors.0 }} //错误信息输出

修改数据

修改数据时,要告诉 django 修改的对象是哪个。

## views.py
form = employModelForm(data=req.POST, instance=obj)

mysql

· 阅读需 5 分钟

mysql的单表查询很简单,但是单表体积增大时,或者涉及到多表查询时就成了难点。本文主要对这些问题做一些记录。

mysql工作原理

mysql服务启动,监听3306端口。外界的客户端,如cmd,django框架,heidisql都视作客户端,用户名密码验证后可以连接到mysql服务。在操作系统中,数据库视作文件夹,每一张表都是一个特殊后缀的文件。 1668775623718.png

数据库的备份和恢复

备份的本质是创建一个sql文件。命令:

mysql -u -p -B db1 db2 > d:\\xxx.sql  -- 按照数据库来备份
mysql -u -p db1 table1 table2 > d:\\yyy.sql -- 按照表来备份
source d:\\xxx.sql -- 恢复

分页

在数据库规模较大的情况下,每次请求都是请求部分,这样就需要分页。

select * from table limit 每页记录数*(页序号-1, 每页记录数

多子句查询的先后顺序

select * from table
group by ..
hanving ..
order by ..
limit ..

自连接

将一张表当作两张表联合查询,需要给表取别名。

select * from table1 as A, table1 as B where ...

表自复制和去重

insert into table select * from table  -- 自复制,也可以用于制作表的备份
------
-- 表格去重流程:先创建新表,将去重的数据写入新表,然后删掉旧表,将新表改名
create table new like old; --创建字段和旧表一致的新表
insert into new select distinct * from old;
drop table old;
alter table new rename old;

外连接

按照下列模式:

select * from table1, table2 where ...

是在两表的笛卡尔积上进行筛选,这样,不符合筛选条件的数据不会列出。有时候我们需要列出不符合筛选条件的数据。外连接分为左右,以左外连接为例,左表的每一项都进入结果中,对于没有匹配上的字段,则赋为Null。语法:

select * from table1 left join table2 on ... -- 筛选条件是on

外键

为了对新插入的数据进行约束,引入了外键。假设,表A作为主表,也就是约束条件,表B作为从表,只能插入表A中主键存在的数据。一旦主表的主键被引用,就不能删除。

create table tab (
id int primary key,
class_id int,
--下面指定外键
foreign key (class_id) references my_class(id), -- my_class是主表。id必须是主键或者unique
)

check约束

注:mysql 8.0.16后开始全面支持check约束。

CREATE TABLE cc (
id INT,
sex VARCHAR(10) CHECK (sex IN('male', 'female'))
);

索引

索引是对一个字段建立的一个二叉树,提升查找速度。是一种空间换时间的策略。对于查找操作多于修改操作的数据库很有必要。

create index_name on table (ziduan)

事务

为了能将多个sql语句作为一个整体执行,事务提出,将增删改包裹起来。

start transaction; -- 开始事务,此时其他会话看不到事务过程中修改的数据结果
-- 执行一些操作 --
savepoint A; -- 设置保存点A
-- 执行一些操作 --
rollback to A; -- 回退到保存点A
rollback; -- 回退到事务开始时状态
commit -- 提交事务,删除所有保存点,此时修改后的数据向其他会话开放

隔离

为了确保事务获得数据的准确性,提出了隔离。默认隔离级别下,不同事务同时开启造成的问题有:

1668952763819.png

事务隔离级别和各级别会出现的问题:

1668952901628.png

select @@transaction_isolation; --查看当前事务隔离级别(mysql8.0+,低版本为select @@tx_isolation)

Django入门和配置

· 阅读需 6 分钟

Django 是 python 的一个 web 后台框架。他的特点是大而全,因此本身命令和代码构架和原生 python 有较大区别,这篇文章是对 django 从入门到项目运行的学习记录。

django-admin startproject name  //创建项目目录
python manage.py runserver //启动项目
django-admin startapp name //创建app

基本概念

在 django 体系中,一个网站由多个 app 组成,每个 app 都有完整的 MTV 体系:

  • M,model,负责建立和数据库的连接
  • T,Template,负责 html
  • V,view,负责处理请求逻辑,比如是请求页面还是数据,是函数形式

新项目初始化设置

app:类名.apps.类名 Config。app 里面有 models.py, views.py.手动创建一个 urls.py。把模块用到的 url 放进去。把处理请求的函数放在 views.py. 最后,回到‘大哥’文件夹的 urls.py, 用 include 方式引入 app 的 urls.

template 创建

template 不是重点。

首先,在根目录下创建 templates 文件夹,在下面建立 html 文件。之后在 settings.py 里注册一下,使项目认识 templates 文件夹。这样,调用 render 函数时,第二个参数字符串就会寻找 html 模板文件。

模板文件同样需要解耦。在 app 下建立 templates folder,下面子文件夹名为 app 的名字。创建模板文件。在 views.py 里改 render 参数的路径。

extends 和 include 引入的模板要放在根目录下的 tempplates folder.

migration 迁移

迁移似乎不是很直观。可以理解为在 models.py 中进行了相关表的创建和修改字段等操作,并应用到数据库中。django 默认的数据库是 sqlite。具体流程是:

  1. 在 model.py 中建立一个 class
  2. 将 class 在 admin.py 中注册
  3. 运行两条命令: makemigrations(会在 migrations 文件夹下建立一个带序号的 py 文件,相当于提交修改)和 migrate(执行修改)

静态文件的部署

静态文件的部署和 setting 有关。这里用 django 推荐的模板语法写。如果我们要配置整个 project 下的静态文件的话,执行此步骤。

 STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"), # 首选project静态文件搜寻路径
'/var/www/static/', # 第二选project静态文件搜寻路径,还可以有第三选,第四选……
)

访问顺序:会先访问 app 下的 static/文件夹下的 myexample.jpg 文件,若 app 下的 static 文件夹中没有该文件,则访问 project 中的 static/文件夹,查看是否有 myexample.jpg 文件,若有则返回,若没有则去/var/www/static/中寻找。参考链接

python manage.py collectstatic

为什么要使用 STATIC_ROOT 呢,是因为当你设置中 DEBUG 为 True 时,django 会自动为你静态文件代理,不过当 DEBUG 为 False 时,意味着你要进入生产环境,那么,你就必须使用 STATIC_ROOT 来指明你的静态文件在哪里,就像 MEDIA_ROOT 一样。部署过程中,输入上面这条命令就将静态文件集中起来了。

完整的静态文件配置如下:

STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
STATIC_ROOT = os.path.join(BASE_DIR, "static")

ORM django 如何与数据库交互

1668480185606.png

ORM

ORM(object relational mapping),对象关系映射,是将数据库的记录视作程序中的对象。

ORM 可以将用户的 python 语句翻译为 sql 语句交给 mysql 等数据库执行。它的好处是不用写很多的 sql 语句,可以连接多种数据库。除了建立数据库需要手动在 mysql 客户端外,建表、删表、操作表内数据都可以用 ORM 完成。models.py 文件可以视为建表操作,每次更改这个文件,就要执行下列命令,将更改应用到数据库中,同时会在 migrations 文件夹内留下历史记录,类似于 github 提交。

python manage.py makemigrations
python manage.py migrate

建表完毕后,要在 views.py 中对表数据修改。首先要正确引入 models 文件,要写全路径:

from app01.models import UserInfo
UserInfo.objects.create(name=user, password=pwd, age=age)
## objects,对象,在orm中,一行数据视作一个对象
## all():所有数据,filter() 就类似与sql的where
## create:增加,update:改,delete:删除