如何使你的网站支持https

简介

HTTPS一般指HTTP over TLS或者HTTP over SSL或者HTTP Secure,是一种通过计算机网略进行安全通信的传输协议,HTTPS经由HTTP进行通信,但是使用SSL/TLS来加密数据包,HTTPS的主要目的是提供对网站服务器的身份认证,保护交换资料的隐私与完整性。
这里使用腾讯云提供的一年免费SSL证书为例,讲解如何使你的网站支持HTTPS。

1 申请证书

首先登录腾讯云的管理控制台,找到SSL证书->证书申请页面,并按照要求填写域名、邮箱等申请资料:

下一步,选择验证方式:

这里推荐使用DNS验证,基本上一分钟之内就可以生效了。

到控制台DNS解析,找到需要添加证书的域名,按照上面要求的内容添加一条解析记录:

然后等待一分钟左右就可以下载到证书了。里面是一个压缩文件,解压后可以看到里面是适用于Apache、Nginx、Tomcat、IIS等各种服务器的私钥配置文件和pem文件

2 配置Nginx

到Nginx的配置目录,默认为/etc/nginx,新建一个cert的文件夹,将下载的证书文件上传到这里。

编辑该域名对应的配置文件,我这里由于配置了虚拟主机所以在/etc/nginx/vhosts/domain.conf,:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 配置http重定向至https
server {
listen 80;
server_name geekhall.cn www.geekhall.cn;
return 301 https://$server_name$request_uri;
}
# 配置https
server {
listen 443 ssl;
server_name geekhall.cn www.geekhall.cn;

# ssl证书地址
ssl_certificate cert/geekhall.cn.pem;
ssl_certificate_key cert/geekhall.cn.key;

# ssl验证配置
ssl_session_timeout 5m; # 缓存有效期
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #加密算法
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #安全链接可选的加密协议
ssl_prefer_server_ciphers on; # 使用服务器端的首选算法

}

重启Nginx服务后使用https访问域名确认生效。

同时提交Github和Gitee

同时提交github和gitee

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1 查看仓库信息
git remote -v

# 2 删除原有远程仓库,然后添加两个远程仓库
git remote rm origin
git remote add github git@github.com:geekhall/geekhall.cn.git
git remote add gitee git@gitee.com:sjdt/geekhall.cn.git

# 2 拉代码,合并两个仓库的历史记录
git pull gitee main --allow-unrelated-histories
git pull github main --allow-unrelated-histories

# 3 设置上游分支
git push --set-upstream github main
git push --set-upstream gitee main

# 3 push 代码
git push gitee main
git push github main


提交脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
usage()
{
echo "使用方法:"
echo "commit.sh"
echo " or"
echo "commit.sh 提交注释"
exit 2
}

if [ $# -eq 1 ]; then
comment=$1
else
comment=`date +'%Y%m%d-%H%M%S'`
fi

git add .
git commit -m "$comment"
git push github
git push gitee

远端自动部署脚本

1
2
3
4
5
6
7
8
9
10
11
cd /usr/share/nginx/html/geekhall.cn
git pull
workon mwd
rm -rf static_dist
python manage.py collectstatic
deactivate
./stopsvr.sh
./startuwsgi.sh
nginx -s stop
nginx

gulp常见问题及解决方法

执行gulp的时候报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜  front git:(main) ✗ gulp
Error: Node Sass does not yet support your current environment: OS X 64-bit with Unsupported runtime (88)
For more information on which environments are supported please see:
https://github.com/sass/node-sass/releases/tag/v4.14.1
at module.exports (/Users/yiny/Sites/geekhall.cn/front/node_modules/node-sass/lib/binding.js:13:13)
at Object.<anonymous> (/Users/yiny/Sites/geekhall.cn/front/node_modules/node-sass/lib/index.js:14:35)
at Module._compile (node:internal/modules/cjs/loader:1108:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
at Module.load (node:internal/modules/cjs/loader:973:32)
at Function.Module._load (node:internal/modules/cjs/loader:813:14)
at Module.require (node:internal/modules/cjs/loader:997:19)
at require (node:internal/modules/cjs/helpers:92:18)
at Object.<anonymous> (/Users/yiny/Sites/geekhall.cn/front/node_modules/gulp-sass/index.js:166:21)
at Module._compile (node:internal/modules/cjs/loader:1108:14)

下面的命令可以修复:

1
npm rebuild node-sass

Nginx虚拟主机的多域名配置

简介

本文的目的是使用Nginx的虚拟主机功能在同一台服务器上配置多个域名,多域名之间可以使用不同架构,比如同时使用php的thinkphp或者Laravel和python的Django。
主要架构思想为使用Nginx作为反向代理,配合php-fpm和fastcgi作为上游服务端提供服务。

1. 目录说明

序号 目录 用途
1 /etc/nginx/nginx.conf Nginx主配置文件
2 /etc/nginx/vhosts/ Nginx虚拟主机配置文件存放目录
3 /etc/nginx/vhosts/aaa.com.conf 网站aaa.com的虚拟主机配置文件存放目录
4 /etc/nginx/vhosts/bbb.com.conf 网站bbb.com的虚拟主机配置文件存放目录
5 /usr/share/nginx/html/aaa.com/ 网站aaa.com的文件存放目录
6 /usr/share/nginx/html/bbb.com/ 网站bbb.com的文件存放目录
7 /etc/php-fpm.d/www.conf php-fpm配置文件

2. Nginx配置

2.1 修改Nginx主配置文件

修改 /etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
http {
include /etc/nginx/conf.d/*.conf;
# 将所有虚拟主机的配置文件都放在vhosts文件夹中
include /etc/nginx/vhosts/*.conf;

# 注释掉Nginx默认的server部分的服务器配置
#server{
# listen 80 default_server;
# ...
#}
}

2.2 修改php版的虚拟主机配置

/etc/nginx/vhosts/aaa.com.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
server {
listen 80;
server_name aaa.com www.aaa.com;
#charset utf-8;
access_log /usr/share/nginx/html/aaa.com/log/host.access.log;
error_log /usr/share/nginx/html/aaa.com/log/error.log;
# gzip off;
root /usr/share/nginx/html/aaa.com/public;
index index.php index.html index.htm;
location / {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
break;
}
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 100d;
}
location ~ .*\.(js|css)?$ {
expires 30d;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include /etc/nginx/fastcgi.conf;
set $fastcgi_script_name2 $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+\.php)(/.+)$") {
set $fastcgi_script_name2 $1;
set $path_info $2;
}
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/aaa.com/public/$fastcgi_script_name2;
fastcgi_param SCRIPT_NAME $fastcgi_script_name2;
}
}

2.3 配置python虚拟环境

使用virtualenv和virtualenvwrapper来新建和管理虚拟环境,相关命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 安装
pip3 install virtualenvwrapper
# 安装好后需要将下面内容添加至~/.bashrc中
export WORKON_HOME=~/Env
source /usr/local/bin/virtualenvwrapper.sh
export LD_LIBRARY_PATH="/usr/local/lib"
export PATH=$PATH:/usr/local/python3/bin/

# 新建虚拟环境
mkvirtualenv my_env

# 切换至虚拟环境
workon my_env

# 退出虚拟环境
deactivate

# 删除虚拟环境
rmvirtualenv my_env

# 列出虚拟环境
lsvirtualenv

2.4 修改Django版的虚拟主机配置

/etc/nginx/vhosts/bbb.com.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream hello{
server unix:///usr/share/nginx/html/hello/hello.sock;
}

server {
listen 80;
server_name bbb.com www.bbb.com;
charset utf-8;
# 发送所有非静态请求至Django服务器
location / {
uwsgi_pass hello;
include /etc/nginx/uwsgi_params;
# root html/moonwhite.design;
# index index.html index.htm index.php;
}
}

3 php-fpm配置

修改/etc/php-fpm.d/www.conf 文件

1
2
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
  • php-fpm启动命令:php-fpm
  • php-fpm停止命令:ps -ef|grep php-fpm|grep master|awk '{print $2}'|xargs kill -QUIT

4 配置使用uwsgi

命令行方式:uwsgi --http :4000 --module hello.wsgi --virtualenv=/root/Env/mwd

配置文件方式:/usr/share/nginx/html/hello/hello.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[uwsgi]

# Django 相关配置
# 必须为绝对路径
# 项目的路径
chdir = /usr/share/nginx/html/hello
# Django 的wsgi文件
module = hello.wsgi
# python 虚拟环境的路径
home = /root/Env/mwd

# 通讯方式:http
#http = :4000

# 进程相关设置
# 主进程
master = true
# 最大数量的工作进程
processes = 10
# 通讯方式:socket
# socket 文件路径
socket = /usr/share/nginx/html/hello/hello.sock
# socket 权限
chomd-socket = 666
# 退出的时候是否清理环境
vacuum = true

配置好之后就可以使用uwsgi --ini hello.ini来启动了。

停止命令:wsgi| grep -v grep |awk '{print $2}'|xargs kill -9

这里需要注意的是uwsgi不要安装在虚拟环境,要安装在系统python环境中。
而Django和相关项目依赖要安装在python虚拟环境中。

5. 配置VCS

1
2
3
4
5
6
# git初始化
git init
# 查看指定远程仓库地址
git remote get-url origin
# 设置远程仓库地址
git remote set-url origin 你新的远程仓库地址

使用gulp4.0搭建前端自动化开发环境

本文要实现的目的是使用gulp整合前端开发环境,当前端scss样式文件,JavaScript文件或者图片资源文件、html文件发生任何改变时,自动触发gulp进行压缩、合并、重命名、并使浏览器自动加载变更内容。

1. npm init

创建一个文件夹用于初始化项目,这里使用front
然后在front目录执行npm init命令,按照提示均默认输入即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
mkdir front
cd front
➜ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (front)
version: (1.0.0)
description: front source
entry point: (index.js)
test command:
git repository:
keywords:
author: moonwhite
license: (ISC)
About to write to /Users/yourusername/front/package.json:

{
"name": "front",
"version": "1.0.0",
"description": "front source",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "moonwhite",
"license": "ISC"
}


Is this OK? (yes) yes
➜ front

关于本文中使用到的package及版本可以参考下面package.json文件,可以将下面代码复制到package.json中,然后执行npm install即可。

1
2
3
4
5
6
7
8
9
10
11
12
"devDependencies": {
"browser-sync": "^2.26.13",
"gulp": "^4.0.2",
"gulp-cache": "^1.1.3",
"gulp-concat": "^2.6.1",
"gulp-cssnano": "^2.1.3",
"gulp-imagemin": "^7.1.0",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.1.0",
"gulp-uglify": "^3.0.2",
"gulp-watch": "^5.0.1"
}

2. 项目目录结构

初始项目目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
├── dist                        # 生产发布目录
│   ├── css # 生产css文件存放目录
│   │   └── sample.min.css # gulp处理后的生产css文件
│   ├── images # 生产图片文件存放目录
│   │   └── *.jpg # 压缩后的生产图片文件
│   ├── js # 生产存放js文件的目录
│   │   └── index.min.js # gulp丑化压缩后的生产js文件
│   └── other
├── gulpfile.js # gulpfile
├── node_modules # npm依赖模块目录
│   └── ...
├── package-lock.json
├── package.json # package文件
├── src # 前台源码目录
│   ├── css # css源码
│   ├── images # 存放原图
│   │   └── *.jpg
│   ├── js # JavaScript源码
│   │   └── *.js
│   └── scss # sass源码
│   └── *.scss
├── templates # HTML模版目录
│   ├── moduledir # 模块文件夹
│   └── moduledir
│   └── *.html
└── otherfile

3. 编写gulpfile

最后gulpfile.js 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const { series, parallel } = require('gulp');

const gulp = require("gulp")
const cssnano = require("gulp-cssnano")
const rename = require('gulp-rename')
const uglify = require('gulp-uglify')
const concat = require('gulp-concat')
const sass = require('gulp-sass')
const cache = require('gulp-cache')
const imagemin = require('gulp-imagemin')
const bs = require('browser-sync').create()

// 定义常用路径
var path = {
'css' : './src/css/',
'scss': './src/scss/',
'js' : './src/js/',
'images': './src/images/',
'dist_css': './dist/css/',
'dist_js': './dist/js/',
'dist_images': './dist/images/',
'templates': './templates/'
};


// sass version
function style(){
// 定义scss源文件位置
return gulp.src(path.scss + '**/*.scss')
// 传递给sass编译器生成css文件
.pipe(sass().on('error', sass.logError))
// 压缩css
.pipe(cssnano())
// 重命名为 filename.min.css
.pipe(rename({suffix:'.min'}))
// 3. 保存编译后的css文件
.pipe(gulp.dest(path.dist_css));
// 4. stream changes to all browser.
// 由于watch 中监视了path.dist_css,所以这里不再需要了。
// .pipe(bs.stream());
}

// Javascript任务
function js(){
return gulp.src(path.js + '*.js')
.pipe(concat('index.js'))
.pipe(uglify({
toplevel: true,
compress: {
drop_console : true
}
}))
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(path.dist_js));
}

// 压缩图片
function images(){
gulp.src(path.images + '*.*')
.pipe(cache(imagemin()))
.pipe(gulp.dest(path.dist_images));
}

function watch(){
bs.init({
server:{
baseDir: './'
}
});
// gulp.watch('./css/**/*.css', css);
// 监视path.scss 目录,如果有变动则执行style任务。
gulp.watch(path.scss + '**/*.scss', style);

// 监视path.js 目录,如果有变动则执行js任务。
gulp.watch(path.js + '**/*.js', js);

// 监视path.images 目录,如果有变动则执行images任务。
gulp.watch(path.images + '*.*', images);

// 监视path.templates 目录,如果有变动则通知浏览器reload。
gulp.watch(path.templates + '**/*.html').on('change', bs.reload);

// 监视path.dist_is 目录,如果有变动则通知浏览器reload。
gulp.watch(path.dist_js + '*.js').on('change', bs.reload);

// 监视path.dist_css 目录,如果有变动则通知浏览器reload。
gulp.watch(path.dist_css + '*.css').on('change', bs.reload);

// 监视path.dist_images 目录,如果有变动则通知浏览器reload。
gulp.watch(path.dist_images + '*.*').on('change', bs.reload);
}

// 导出任务,使得可以在命令行使用。
exports.style = style;
exports.js = js;
exports.images = images;
exports.watch = watch;

最后,在front目录执行gulp watch命令即可,效果如下:

前端自动化开发环境搭建笔记

1. nvm的安装

nvm(node version manager): 是node.js的版本管理工具,

1.1 安装nvm

官方安装说明文档
安装命令:

1
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash

或者

1
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash

1.2 配置环境变量

然后还需要把下面环境变量内容添加到.bash_profile中,如果使用oh-my-zsh的话配置到.zshrc中

1
2
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

1.3 常用命令

1
2
3
4
5
6
7
8
9
10
11
12
nvm install 8.0.0                     安装特定版本的node
nvm use 8.0 使用最新可用的8.0.x的release版本
nvm run 6.10.3 app.js 使用node 6.10.3运行app.js
nvm exec 4.8.3 node app.js 使用4.8.3版本的node运行 app.js
nvm alias default 8.1.0 设定node默认版本
nvm alias default node 总是默认设置最新可用的node版本
nvm install node 安装最新可用版本的node
nvm use node 使用最新可用版本的node
nvm install --lts 安装最新的LTS版本的node
nvm use --lts 使用最新的LTS版本的node
nvm set-colors cgYmW 设置文本颜色为: cyan, green, bold yellow, magenta, and white

2. 安装node和npm

安装完nvm之后,我们就可以使用nvm来安装node了。

1
2
3
4
# 安装最新可用版本的node
nvm install node
# 安装最新的LTS版本的node
nvm install --lts

npm类似于python的pip,可以方便的安装一些前端开发的包。
在安装完node之后npm就也自动的被安装了

3. gulp的安装及使用

gulp用来自动化开发流程,比如saas转css,css和js压缩等。

3.1 安装gulp

1
2
3
4
5
6
# 本地安装
npm install gulp
# --save-dev表示写入package.json文件
npm install gulp --save-dev
# 参数-g表示global,使得gulp可以在全局环境比如系统命令行中使用。
npm install gulp -g

3.2 gulp的使用

在项目根目录创建一个gulpfile.js,然后在gulpfile.js中插入如下代码:

1
2
3
4
5
6
7
8
9
10
var gulp = require("gulp")
var cssnano = require("gulp-cssnano")

// 定义css文件改动任务
gulp.task("css", done => {
gulp.src("./css/*.css")
.pipe(cssnano())
.pipe(gulp.dest("./dist/css"))
done();
});

3.3 gulp常用命令及插件

1
gulp task #执行gulp命令

常用gulp包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 文件重命名
npm install gulp-rename --save-dev

# css压缩
npm install gulp-cssnano --save-dev

# js压缩
npm install gulp-uglifu --save-dev

# 合并多个文件
npm install gulp-concat --save-dev

# 压缩图片
npm install gulp-imagemin --save-dev

# 图片缓存
npm install gulp-cache --save-dev

# 文件监控自动执行任务
npm install gulp-watch --save-dev

# 浏览器自动同步
npm install browser-sync --save-dev


3.4 gulp常见问题

任务未完成错误

使用gulp css命令的时候,提示如下信息:

1
2
[21:41:30] The following tasks did not complete: css
[21:41:30] Did you forget to signal async completion?

错误代码:

1
2
3
4
5
6
7
8
9
var gulp = require("gulp")
var cssnano = require("gulp-cssnano")

// 定义css文件改动任务
gulp.task("css", function() {
gulp.src("./css/*.css")
.pipe(cssnano())
.pipe(gulp.dest("./dist/css"))
});

修改为如下格式即可解决:

1
2
3
4
5
6
7
8
9
10
var gulp = require("gulp")
var cssnano = require("gulp-cssnano")

// 定义css文件改动任务
gulp.task("css", done => {
gulp.src("./css/*.css")
.pipe(cssnano())
.pipe(gulp.dest("./dist/css"))
done();
});

Oracle Partition相关操作

常用语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--查看表分区
select partition_name, high_value from user_tab_partitions t where table_name = 'tablename'

--查询表分区绑定的字段名
select * from user_part_key-columns t where name='tablename'

-- 查看当前表分区的具体状况
select * from user_tab_partitions t where table_name = 'tablename'

-- 增加表分区
alter table tablename add partition partitionname values
less than ('20201212') logging nocompress;

-- 修改分区名称
alter table tablename rename partition oldpartname to newpartname;




Django笔记:7.views视图

Paginator常用属性和方法

  1. count:总共有多少条数据。
  2. num_pages:总共有多少页。
  3. page_range:页面的区间,比如有三页,那么就range(1,4)

Page 常用属性和方法

  1. has_next: 是否还有下一页。
  2. has_previous: 是否还有下一页。
  3. next_page_number: 下一页的页码。
  4. previous_page_number: 上一页的页码。
  5. number: 当前页。
  6. start_index: 当前页面的第一条数据的索引值。
  7. end_index: 当前页面最后一条数据的索引值。

Django笔记:6.ORM

ORM对数据库的基本操作

添加数据

只要使用ORM模型创建一个对象。然后再调用这个ORM模型的save方法就可以保存了。
示例代码如下:

1
2
book = Book(name='西游记',author='吴承恩',price=100)
book.save()

查找数据

所有的查找工作都是使用模型上的objects属性来完成的。当然也可以自定义查询对象。这部分功能会在后面讲到。

  1. 根据主键进行查找:使用主键进行查找。可以使用objects.get方法。然后传递pk=xx的方式进行查找。示例代码如下:

    1
    book = Book.objects.get(pk=2)
  2. 根据其他字段进行查找:可以使用objects.filter方法进行查找。示例代码如下:

    1
    books = Book.objects.filter(name='三国演义')

    使用filter方法返回来的是一个QuerySet对象。这个对象类似于列表。我们可以使用这个对象的first方法来获取第一个值。

删除数据

首先查找到对应的数据模型。然后再执行这个模型的delete方法即可删除。示例代码如下:

1
2
book = Book.objects.get(pk=1)
book.delete()

修改数据

首先查找到对应的数据模型。然后修改这个模型上的属性的值。再执行save方法即可修改完成。示例代码如下:

1
2
3
book = Book.objects.get(pk=2)
book.price = 200
book.save()

常用Field笔记

naive时间和aware时间

什么是naive时间?什么是aware时间?

  1. naive时间:不知道自己的时间表示的是哪个时区的。也就是不知道自己几斤几两。比较幼稚。
  2. aware时间:知道自己的时间表示的是哪个时区的。也就是比较清醒。

pytz库

专门用来处理时区的库。这个库会经常更新一些时区的数据,不需要我们担心。并且这个库在安装Django的时候会默认的安装。如果没有安装,那么可以通过pip install pytz的方式进行安装。

astimezone方法

将一个时区的时间转换为另外一个时区的时间。这个方法只能被aware类型的时间调用。不能被navie类型的时间调用。
示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
import pytz
from datetime import datetime
now = datetime.now() # 这是一个navie类型的时间
utc_timezone = pytz.timezone("UTC") # 定义UTC的时区对象
utc_now = now.astimezone(utc_timezone) # 将当前的时间转换为UTC时区的时间
>> ValueError: astimezone() cannot be applied to a naive datetime # 会抛出一个异常,原因就是因为navie类型的时间不能调用astimezone方法


now = now.replace(tzinfo=pytz.timezone('Asia/Shanghai'))
utc_now = now.astimezone(utc_timezone)
# 这时候就可以正确的转换。

replace方法

可以将一个时间的某些属性进行更改。

django.utils.timezone.now方法

会根据settings.py中是否设置了USE_TZ=True获取当前的时间。如果设置了,那么就获取一个aware类型的UTC时间。如果没有设置,那么就会获取一个navie类型的时间。

django.utils.timezone.localtime方法

会根据setting.py中的TIME_ZONE来将一个aware类型的时间转换为TIME_ZONE指定时区的时间。

DateField

日期类型。在Python中是datetime.date类型,可以记录年月日。在映射到数据库中也是date类型。使用这个Field可以传递以下几个参数:

  1. auto_now:在每次这个数据保存的时候,都使用当前的时间。比如作为一个记录修改日期的字段,可以将这个属性设置为True
  2. auto_now_add:在每次数据第一次被添加进去的时候,都使用当前的时间。比如作为一个记录第一次入库的字段,可以将这个属性设置为True

DateTimeField

日期时间类型,类似于DateField。不仅仅可以存储日期,还可以存储时间。映射到数据库中是datetime类型。这个Field也可以使用auto_nowauto_now_add两个属性。

TimeField

时间类型。在数据库中是time类型。在Python中是datetime.time类型。

https://docs.djangoproject.com/en/2.0/topics/i18n/timezones/

EmailField

类似于CharField。在数据库底层也是一个varchar类型。最大长度是254个字符。

FileField

用来存储文件的。这个请参考后面的文件上传章节部分。

ImageField

用来存储图片文件的。这个请参考后面的图片上传章节部分。

FloatField

浮点类型。映射到数据库中是float类型。

IntegerField

整形。值的区间是-2147483648——2147483647

BigIntegerField

大整形。值的区间是-9223372036854775808——9223372036854775807

PositiveIntegerField

正整形。值的区间是0——2147483647

SmallIntegerField

小整形。值的区间是-32768——32767

PositiveSmallIntegerField

正小整形。值的区间是0——32767

TextField

大量的文本类型。映射到数据库中是longtext类型。

UUIDField

只能存储uuid格式的字符串。uuid是一个32位的全球唯一的字符串,一般用来作为主键。

URLField

类似于CharField,只不过只能用来存储url格式的字符串。并且默认的max_length是200。

Field常用的参数

null

如果设置为TrueDjango将会在映射表的时候指定是否为空。默认是为False。在使用字符串相关的Field(CharField/TextField)的时候,官方推荐尽量不要使用这个参数,也就是保持默认值False。因为Django在处理字符串相关的Field的时候,即使这个Fieldnull=False,如果你没有给这个Field传递任何值,那么Django也会使用一个空的字符串""来作为默认值存储进去。因此如果再使用null=TrueDjango会产生两种空值的情形(NULL或者空字符串)。如果想要在表单验证的时候允许这个字符串为空,那么建议使用blank=True。如果你的FieldBooleanField,那么对应的可空的字段则为NullBooleanField

blank

标识这个字段在表单验证的时候是否可以为空。默认是False
这个和null是有区别的,null是一个纯数据库级别的。而blank是表单验证级别的。

db_column

这个字段在数据库中的名字。如果没有设置这个参数,那么将会使用模型中属性的名字。

default

默认值。可以为一个值,或者是一个函数,但是不支持lambda表达式。并且不支持列表/字典/集合等可变的数据结构。

primary_key

是否为主键。默认是False

unique

在表中这个字段的值是否唯一。一般是设置手机号码/邮箱等。

更多Field参数请参考官方文档:https://docs.djangoproject.com/zh-hans/2.0/ref/models/fields/

模型中Meta配置

对于一些模型级别的配置。我们可以在模型中定义一个类,叫做Meta。然后在这个类中添加一些类属性来控制模型的作用。比如我们想要在数据库映射的时候使用自己指定的表名,而不是使用模型的名称。那么我们可以在Meta类中添加一个db_table的属性。示例代码如下:

1
2
3
4
5
6
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")

class Meta:
db_table = 'book_model'

以下将对Meta类中的一些常用配置进行解释。

db_table

这个模型映射到数据库中的表名。如果没有指定这个参数,那么在映射的时候将会使用模型名来作为默认的表名。

ordering

设置在提取数据的排序方式。后面章节会讲到如何查找数据。比如我想在查找数据的时候根据添加的时间排序,那么示例代码如下:

1
2
3
4
5
6
7
8
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
pub_date = models.DateTimeField(auto_now_add=True)

class Meta:
db_table = 'book_model'
ordering = ['pub_date']

更多的配置后面会慢慢介绍到。
官方文档:https://docs.djangoproject.com/en/2.0/ref/models/options/

表关系笔记

一对多

  1. 应用场景:比如文章和作者之间的关系。一个文章只能由一个作者编写,但是一个作者可以写多篇文章。文章和作者之间的关系就是典型的多对一的关系。
  2. 实现方式:一对多或者多对一,都是通过ForeignKey来实现的。还是以文章和作者的案例进行讲解。
1
2
3
4
5
6
7
8
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)

class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey("User",on_delete=models.CASCADE)

那么以后在给Article对象指定author,就可以使用以下代码来完成:

1
2
3
4
5
6
article = Article(title='abc',content='123')
author = User(username='zhiliao',password='111111')
# 要先保存到数据库中
author.save()
article.author = author
article.save()

并且以后如果想要获取某个用户下所有的文章,可以通过article_set来实现。示例代码如下:

1
2
3
4
5
user = User.objects.first()
# 获取第一个用户写的所有文章
articles = user.article_set.all()
for article in articles:
print(article)

并且如果想要将文章添加到某个分类中。可以使用一下的方式:

1
2
3
4
5
6
category = Category.objects.first()

article = Article(title='bbb',content='vvv')
article.author = FrontUser.objects.first()

category.article_set.add(article,bulk=False)
  • 使用bulk=False,那么Django会自动的保存article,而不需要在添加到category之前先保存article。
  • 或者是另外一种解决方式是,在添加到category.article_set中之前,先将article保存到数据库中。但是如果article.category不能为空,那么就产生一种死循环了,article没有category不能保存,而将article添加到cateogry.artile_set中,又需要article之前是已经存储到数据库中的。
  • 如果是上面的那种需求,建议使用bulk=False的解决方案。

一对一

  1. 在Django中一对一是通过models.OnetToOneField来实现的。这个OneToOneField其实本质上就是一个外键,只不过这个外键有一个唯一约束(unique key),来实现一对一。

  2. 以后如果想要反向引用,那么是通过引用的模型的名字转换为小写的形式进行访问。比如以下模型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class FrontUser(models.Model):
    username = models.CharField(max_length=200)

    class UserExtension(models.Model):
    school = models.CharField(max_length=100)
    user = models.OneToOneField("FrontUser",on_delete=models.CASCADE)

    # 通过userextension来访问UserExtension对象
    user = FrontUser.objects.first()
    print(user.userextension)

    UserExtension的对象,可以通过user来访问到对应的user对象。并且FrontUser对象可以使用userextension来访问对应的UserExtension对象。
    如果不想使用Django默认的引用属性名字。那么可以在OneToOneField中添加一个related_name参数。示例代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class FrontUser(models.Model):
    username = models.CharField(max_length=200)

    class UserExtension(models.Model):
    school = models.CharField(max_length=100)
    user = models.OneToOneField("FrontUser",on_delete=models.CASCADE,related_name='extension')

    # 通过extension来访问到UserExtension对象
    user = FrontUser.objects.first()
    print(user.extension)

    那么以后就FrontUser的对象就可以通过extension属性来访问到对应的UserExtension对象。

多对多

  1. 应用场景:比如文章和标签的关系。一篇文章可以有多个标签,一个标签可以被多个文章所引用。因此标签和文章的关系是典型的多对多的关系。

  2. 实现方式:Django为这种多对多的实现提供了专门的Field。叫做ManyToManyField。还是拿文章和标签为例进行讲解。示例代码如下:

1
2
3
4
5
6
7
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
tags = models.ManyToManyField("Tag",related_name="articles")

class Tag(models.Model):
name = models.CharField(max_length=50)

在数据库层面,实际上Django是为这种多对多的关系建立了一个中间表。这个中间表分别定义了两个外键,引用到articletag两张表的主键。

Mac下不同版本Python

简介

官网下载升级安装了Python3.9,之前brew安装过python3.8,Mac自带了2.7,Pycharm使用virtualenv安装过3.7,各种情况的默认目录如下:

来源 python安装路径
系统默认(2.7) /System/Library/Frameworks/Python.framework/Versions/2.x
pycharm(3.7) /Users/username/PycharmProjects/venv/python3.7
brew(3.8) /usr/local/Cellar/python@3.8/3.8.5/bin/
官网pkg安装(3.9) /Library/Frameworks/Python.framework/Versions/3.x

写入环境变量

1
2
vi ~/.bash_provile
export PATH=$PATH:/usr/local/bin/python3

preference -> project Interpreter -> 右侧的Add按钮
添加System Interpreter

添加Pipenv Environment