提交 0640abb2 编写于 作者: J jackfrued

更新了Linux、数据库和Django部分的文档

上级 87de54a0
......@@ -92,19 +92,19 @@ Linux系统的命令通常都是如下所示的格式:
1. 获取登录信息 - **w** / **who** / **last**/ **lastb**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# w
[root ~]# w
23:31:16 up 12:16, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 182.139.66.250 23:03 4.00s 0.02s 0.00s w
jackfrue pts/1 182.139.66.250 23:26 3:56 0.00s 0.00s -bash
[root@izwz97tbgo9lkabnat2lo8z ~]# who
[root ~]# who
root pts/0 2018-04-12 23:03 (182.139.66.250)
jackfrued pts/1 2018-04-12 23:26 (182.139.66.250)
[root@izwz97tbgo9lkabnat2lo8z ~]# who am i
[root ~]# who am i
root pts/0 2018-04-12 23:03 (182.139.66.250)
[root@izwz97tbgo9lkabnat2lo8z ~]# who mom likes
[root ~]# who mom likes
root pts/0 2018-04-12 23:03 (182.139.66.250)
[root@izwz97tbgo9lkabnat2lo8z ~]# last
[root ~]# last
root pts/0 117.136.63.184 Sun May 26 18:57 still logged in
reboot system boot 3.10.0-957.10.1. Mon May 27 02:52 - 19:10 (-7:-42)
root pts/4 117.136.63.184 Sun May 26 18:51 - crash (08:01)
......@@ -128,17 +128,17 @@ Linux系统的命令通常都是如下所示的格式:
3. 查看命令的说明和位置 - **whatis** / **which** / **whereis**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# whatis ps
[root ~]# whatis ps
ps (1) - report a snapshot of the current processes.
[root@izwz97tbgo9lkabnat2lo8z ~]# whatis python
[root ~]# whatis python
python (1) - an interpreted, interactive, object-oriented programming language
[root@izwz97tbgo9lkabnat2lo8z ~]# whereis ps
[root ~]# whereis ps
ps: /usr/bin/ps /usr/share/man/man1/ps.1.gz
[root@izwz97tbgo9lkabnat2lo8z ~]# whereis python
[root ~]# whereis python
python: /usr/bin/python /usr/bin/python2.7 /usr/lib/python2.7 /usr/lib64/python2.7 /etc/python /usr/include/python2.7 /usr/share/man/man1/python.1.gz
[root@izwz97tbgo9lkabnat2lo8z ~]# which ps
[root ~]# which ps
/usr/bin/ps
[root@izwz97tbgo9lkabnat2lo8z ~]# which python
[root ~]# which python
/usr/bin/python
```
......@@ -202,22 +202,22 @@ Linux系统的命令通常都是如下所示的格式:
8. 重启和关机 - **reboot** / **shutdown**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# shutdown -h +5
[root ~]# shutdown -h +5
Shutdown scheduled for Sun 2019-05-26 19:34:27 CST, use 'shutdown -c' to cancel.
[root@izwz97tbgo9lkabnat2lo8z ~]#
Broadcast message from root@izwz97tbgo9lkabnat2lo8z (Sun 2019-05-26 19:29:27 CST):
[root ~]#
Broadcast message from root (Sun 2019-05-26 19:29:27 CST):
The system is going down for power-off at Sun 2019-05-26 19:34:27 CST!
[root@izwz97tbgo9lkabnat2lo8z ~]# shutdown -c
[root ~]# shutdown -c
Broadcast message from root@izwz97tbgo9lkabnat2lo8z (Sun 2019-05-26 19:30:22 CST):
Broadcast message from root (Sun 2019-05-26 19:30:22 CST):
The system shutdown has been cancelled at Sun 2019-05-26 19:31:22 CST!
[root@izwz97tbgo9lkabnat2lo8z ~]# shutdown -r 23:58
[root ~]# shutdown -r 23:58
Shutdown scheduled for Sun 2019-05-26 23:58:00 CST, use 'shutdown -c' to cancel.
[root@izwz97tbgo9lkabnat2lo8z ~]# shutdown -c
[root ~]# shutdown -c
Broadcast message from root@izwz97tbgo9lkabnat2lo8z (Sun 2019-05-26 19:31:06 CST):
Broadcast message from root (Sun 2019-05-26 19:31:06 CST):
The system shutdown has been cancelled at Sun 2019-05-26 19:32:06 CST!
```
......@@ -247,19 +247,19 @@ Linux系统的命令通常都是如下所示的格式:
1. 创建/删除空目录 - **mkdir** / **rmdir**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# mkdir abc
[root@iZwz97tbgo9lkabnat2lo8Z ~]# mkdir -p xyz/abc
[root@iZwz97tbgo9lkabnat2lo8Z ~]# rmdir abc
[root ~]# mkdir abc
[root ~]# mkdir -p xyz/abc
[root ~]# rmdir abc
```
2. 创建/删除文件 - **touch** / **rm**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# touch readme.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# touch error.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# rm error.txt
[root ~]# touch readme.txt
[root ~]# touch error.txt
[root ~]# rm error.txt
rm: remove regular empty file ‘error.txt’? y
[root@iZwz97tbgo9lkabnat2lo8Z ~]# rm -rf xyz
[root ~]# rm -rf xyz
```
- `touch`命令用于创建空白文件或修改文件时间。在Linux系统中一个文件有三种时间:
......@@ -286,7 +286,7 @@ Linux系统的命令通常都是如下所示的格式:
5. 查看文件内容 - **cat** / **tac** / **head** / **tail** / **more** / **less** / **rev** / **od**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wget http://www.sohu.com/ -O sohu.html
[root ~]# wget http://www.sohu.com/ -O sohu.html
--2018-06-20 18:42:34-- http://www.sohu.com/
Resolving www.sohu.com (www.sohu.com)... 14.18.240.6
Connecting to www.sohu.com (www.sohu.com)|14.18.240.6|:80... connected.
......@@ -295,9 +295,9 @@ Linux系统的命令通常都是如下所示的格式:
Saving to: ‘sohu.html’
100%[==================================================>] 212,527 --.-K/s in 0.03s
2018-06-20 18:42:34 (7.48 MB/s) - ‘sohu.html’ saved [212527/212527]
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat sohu.html
[root ~]# cat sohu.html
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# head -10 sohu.html
[root ~]# head -10 sohu.html
<!DOCTYPE html>
<html>
<head>
......@@ -307,12 +307,12 @@ Linux系统的命令通常都是如下所示的格式:
<meta name="shenma-site-verification" content="1237e4d02a3d8d73e96cbd97b699e9c3_1504254750">
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"/>
[root@iZwz97tbgo9lkabnat2lo8Z ~]# tail -2 sohu.html
[root ~]# tail -2 sohu.html
</body>
</html>
[root@iZwz97tbgo9lkabnat2lo8Z ~]# less sohu.html
[root ~]# less sohu.html
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat -n sohu.html | more
[root ~]# cat -n sohu.html | more
...
```
......@@ -321,13 +321,13 @@ Linux系统的命令通常都是如下所示的格式:
6. 拷贝/移动文件 - **cp** / **mv**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# mkdir backup
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cp sohu.html backup/
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cd backup
[root@iZwz97tbgo9lkabnat2lo8Z backup]# ls
[root ~]# mkdir backup
[root ~]# cp sohu.html backup/
[root ~]# cd backup
[root backup]# ls
sohu.html
[root@iZwz97tbgo9lkabnat2lo8Z backup]# mv sohu.html sohu_index.html
[root@iZwz97tbgo9lkabnat2lo8Z backup]# ls
[root backup]# mv sohu.html sohu_index.html
[root backup]# ls
sohu_index.html
```
......@@ -453,41 +453,41 @@ Linux系统的命令通常都是如下所示的格式:
- **iconv** - 编码转换
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat foo.txt
[root ~]# cat foo.txt
grape
apple
pitaya
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat bar.txt
[root ~]# cat bar.txt
100
200
300
400
[root@iZwz97tbgo9lkabnat2lo8Z ~]# paste foo.txt bar.txt
[root ~]# paste foo.txt bar.txt
grape 100
apple 200
pitaya 300
400
[root@iZwz97tbgo9lkabnat2lo8Z ~]# paste foo.txt bar.txt > hello.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cut -b 4-8 hello.txt
[root ~]# paste foo.txt bar.txt > hello.txt
[root ~]# cut -b 4-8 hello.txt
pe 10
le 20
aya 3
0
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat hello.txt | tr '\t' ','
[root ~]# cat hello.txt | tr '\t' ','
grape,100
apple,200
pitaya,300
,400
[root@izwz97tbgo9lkabnat2lo8z ~]# split -l 100 sohu.html hello
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wget https://www.baidu.com/img/bd_logo1.png
[root@iZwz97tbgo9lkabnat2lo8Z ~]# file bd_logo1.png
[root ~]# split -l 100 sohu.html hello
[root ~]# wget https://www.baidu.com/img/bd_logo1.png
[root ~]# file bd_logo1.png
bd_logo1.png: PNG image data, 540 x 258, 8-bit colormap, non-interlaced
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wc sohu.html
[root ~]# wc sohu.html
2979 6355 212527 sohu.html
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wc -l sohu.html
[root ~]# wc -l sohu.html
2979 sohu.html
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wget http://www.qq.com -O qq.html
[root@iZwz97tbgo9lkabnat2lo8Z ~]# iconv -f gb2312 -t utf-8 qq.html
[root ~]# wget http://www.qq.com -O qq.html
[root ~]# iconv -f gb2312 -t utf-8 qq.html
```
#### 管道和重定向
......@@ -497,14 +497,14 @@ Linux系统的命令通常都是如下所示的格式:
例子:查找当前目录下文件个数。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# find ./ | wc -l
[root ~]# find ./ | wc -l
6152
```
例子:列出当前路径下的文件和文件夹,给每一项加一个编号。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls | cat -n
[root ~]# ls | cat -n
1 dump.rdb
2 mongodb-3.6.5
3 Python-3.6.5
......@@ -515,13 +515,13 @@ Linux系统的命令通常都是如下所示的格式:
例子:查找record.log中包含AAA,但不包含BBB的记录的总数
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat record.log | grep AAA | grep -v BBB | wc -l
[root ~]# cat record.log | grep AAA | grep -v BBB | wc -l
```
2. 输出重定向和错误重定向 - **\>** / **>>** / **2\>**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat readme.txt
[root ~]# cat readme.txt
banana
apple
grape
......@@ -530,8 +530,8 @@ Linux系统的命令通常都是如下所示的格式:
watermelon
pear
pitaya
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat readme.txt | sort | uniq > result.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat result.txt
[root ~]# cat readme.txt | sort | uniq > result.txt
[root ~]# cat result.txt
apple
banana
grape
......@@ -543,15 +543,15 @@ Linux系统的命令通常都是如下所示的格式:
3. 输入重定向 - **\<**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# echo 'hello, world!' > hello.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wall < hello.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]#
Broadcast message from root@iZwz97tbgo9lkabnat2lo8Z (Wed Jun 20 19:43:05 2018):
[root ~]# echo 'hello, world!' > hello.txt
[root ~]# wall < hello.txt
[root ~]#
Broadcast message from root (Wed Jun 20 19:43:05 2018):
hello, world!
[root@iZwz97tbgo9lkabnat2lo8Z ~]# echo 'I will show you some code.' >> hello.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wall < hello.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]#
Broadcast message from root@iZwz97tbgo9lkabnat2lo8Z (Wed Jun 20 19:43:55 2018):
[root ~]# echo 'I will show you some code.' >> hello.txt
[root ~]# wall < hello.txt
[root ~]#
Broadcast message from root (Wed Jun 20 19:43:55 2018):
hello, world!
I will show you some code.
```
......@@ -561,7 +561,7 @@ Linux系统的命令通常都是如下所示的格式:
下面的命令除了在终端显示命令`ls`的结果之外,还会追加输出到`ls.txt`文件中。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls | tee -a ls.txt
[root ~]# ls | tee -a ls.txt
```
#### 别名
......@@ -569,20 +569,20 @@ Linux系统的命令通常都是如下所示的格式:
1. **alias**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# alias ll='ls -l'
[root@iZwz97tbgo9lkabnat2lo8Z ~]# alias frm='rm -rf'
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ll
[root ~]# alias ll='ls -l'
[root ~]# alias frm='rm -rf'
[root ~]# ll
...
drwxr-xr-x 2 root root 4096 Jun 20 12:52 abc
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# frm abc
[root ~]# frm abc
```
2. **unalias**
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# unalias frm
[root@iZwz97tbgo9lkabnat2lo8Z ~]# frm sohu.html
[root ~]# unalias frm
[root ~]# frm sohu.html
-bash: frm: command not found
```
......@@ -593,7 +593,7 @@ Linux系统的命令通常都是如下所示的格式:
sed是操作、过滤和转换文本内容的工具。假设有一个名为fruit.txt的文件,内容如下所示。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# cat -n fruit.txt
[root ~]# cat -n fruit.txt
1 banana
2 grape
3 apple
......@@ -604,7 +604,7 @@ Linux系统的命令通常都是如下所示的格式:
接下来,我们在第2行后面添加一个pitaya。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sed '2a pitaya' fruit.txt
[root ~]# sed '2a pitaya' fruit.txt
banana
grape
pitaya
......@@ -618,7 +618,7 @@ Linux系统的命令通常都是如下所示的格式:
在第2行前面插入一个waxberry。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sed '2i waxberry' fruit.txt
[root ~]# sed '2i waxberry' fruit.txt
banana
waxberry
grape
......@@ -630,7 +630,7 @@ Linux系统的命令通常都是如下所示的格式:
删除第3行。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sed '3d' fruit.txt
[root ~]# sed '3d' fruit.txt
banana
grape
watermelon
......@@ -640,7 +640,7 @@ Linux系统的命令通常都是如下所示的格式:
删除第2行到第4行。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sed '2,4d' fruit.txt
[root ~]# sed '2,4d' fruit.txt
banana
orange
```
......@@ -648,7 +648,7 @@ Linux系统的命令通常都是如下所示的格式:
将文本中的字符a替换为@。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sed 's#a#@#' fruit.txt
[root ~]# sed 's#a#@#' fruit.txt
b@nana
gr@pe
@pple
......@@ -659,7 +659,7 @@ Linux系统的命令通常都是如下所示的格式:
将文本中的字符a替换为@,使用全局模式。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sed 's#a#@#g' fruit.txt
[root ~]# sed 's#a#@#g' fruit.txt
b@n@n@
gr@pe
@pple
......@@ -674,7 +674,7 @@ Linux系统的命令通常都是如下所示的格式:
假设有一个名为fruit2.txt的文件,内容如下所示。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# cat fruit2.txt
[root ~]# cat fruit2.txt
1 banana 120
2 grape 500
3 apple 1230
......@@ -685,14 +685,14 @@ Linux系统的命令通常都是如下所示的格式:
显示文件的第3行。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# awk 'NR==3' fruit2.txt
[root ~]# awk 'NR==3' fruit2.txt
3 apple 1230
```
显示文件的第2列。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# awk '{print $2}' fruit2.txt
[root ~]# awk '{print $2}' fruit2.txt
banana
grape
apple
......@@ -703,7 +703,7 @@ Linux系统的命令通常都是如下所示的格式:
显示文件的最后一列。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# awk '{print $NF}' fruit2.txt
[root ~]# awk '{print $NF}' fruit2.txt
120
500
1230
......@@ -714,7 +714,7 @@ Linux系统的命令通常都是如下所示的格式:
输出末尾数字大于等于300的行。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# awk '{if($3 >= 300) {print $0}}' fruit2.txt
[root ~]# awk '{if($3 >= 300) {print $0}}' fruit2.txt
2 grape 500
3 apple 1230
5 orange 400
......@@ -727,8 +727,8 @@ Linux系统的命令通常都是如下所示的格式:
1. 创建和删除用户 - **useradd** / **userdel**
```Shell
[root@izwz97tbgo9lkabnat2lo8z home]# useradd hellokitty
[root@izwz97tbgo9lkabnat2lo8z home]# userdel hellokitty
[root home]# useradd hellokitty
[root home]# userdel hellokitty
```
- `-d` - 创建用户时为用户指定用户主目录
......@@ -741,7 +741,7 @@ Linux系统的命令通常都是如下所示的格式:
3. 修改密码 - **passwd**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# passwd hellokitty
[root ~]# passwd hellokitty
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
......@@ -765,16 +765,16 @@ Linux系统的命令通常都是如下所示的格式:
5. 切换用户 - **su**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# su hellokitty
[hellokitty@izwz97tbgo9lkabnat2lo8z root]$
[root ~]# su hellokitty
[hellokitty root]$
```
6. 以管理员身份执行命令 - **sudo**
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ ls /root
[hellokitty ~]$ ls /root
ls: cannot open directory /root: Permission denied
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ sudo ls /root
[hellokitty ~]$ sudo ls /root
[sudo] password for hellokitty:
```
......@@ -812,7 +812,7 @@ Linux系统的命令通常都是如下所示的格式:
发送方:
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# write hellokitty
[root ~]# write hellokitty
Dinner is on me.
Call me at 6pm.
```
......@@ -820,8 +820,8 @@ Linux系统的命令通常都是如下所示的格式:
接收方:
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$
Message from root@izwz97tbgo9lkabnat2lo8z on pts/0 at 17:41 ...
[hellokitty ~]$
Message from root on pts/0 at 17:41 ...
Dinner is on me.
Call me at 6pm.
EOF
......@@ -829,13 +829,13 @@ Linux系统的命令通常都是如下所示的格式:
10. 查看/设置是否接收其他用户发送的消息 - **mesg**
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ mesg
is y
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ mesg n
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ mesg
is n
```
```Shell
[hellokitty ~]$ mesg
is y
[hellokitty ~]$ mesg n
[hellokitty ~]$ mesg
is n
```
### 文件系统
......@@ -872,17 +872,17 @@ Linux系统的命令通常都是如下所示的格式:
1. **chmod** - 改变文件模式比特。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
[root ~]# ls -l
...
-rw-r--r-- 1 root root 211878 Jun 19 16:06 sohu.html
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# chmod g+w,o+w sohu.html
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
[root ~]# chmod g+w,o+w sohu.html
[root ~]# ls -l
...
-rw-rw-rw- 1 root root 211878 Jun 19 16:06 sohu.html
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# chmod 644 sohu.html
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
[root ~]# chmod 644 sohu.html
[root ~]# ls -l
...
-rw-r--r-- 1 root root 211878 Jun 19 16:06 sohu.html
...
......@@ -896,12 +896,12 @@ Linux系统的命令通常都是如下所示的格式:
2. **chown** - 改变文件所有者。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
[root ~]# ls -l
...
-rw-r--r-- 1 root root 54 Jun 20 10:06 readme.txt
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# chown hellokitty readme.txt
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
[root ~]# chown hellokitty readme.txt
[root ~]# ls -l
...
-rw-r--r-- 1 hellokitty root 54 Jun 20 10:06 readme.txt
...
......@@ -914,7 +914,7 @@ Linux系统的命令通常都是如下所示的格式:
1. 列出文件系统的磁盘使用状况 - **df**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# df -h
[root ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 5.0G 33G 14% /
devtmpfs 486M 0 486M 0% /dev
......@@ -927,7 +927,7 @@ Linux系统的命令通常都是如下所示的格式:
2. 磁盘分区表操作 - **fdisk**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# fdisk -l
[root ~]# fdisk -l
Disk /dev/vda: 42.9 GB, 42949672960 bytes, 83886080 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
......@@ -947,7 +947,7 @@ Linux系统的命令通常都是如下所示的格式:
4. 格式化文件系统 - **mkfs**。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ mkfs -t ext4 -v /dev/sdb
[root ~]# mkfs -t ext4 -v /dev/sdb
```
- `-t` - 指定文件系统的类型。
......@@ -969,7 +969,7 @@ Linux系统的命令通常都是如下所示的格式:
1. 启动vim。可以通过`vi`或`vim`命令来启动vim,启动时可以指定文件名来打开一个文件,如果没有指定文件名,也可以在保存的时候指定文件名。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# vim guess.py
[root ~]# vim guess.py
```
2. 命令模式、编辑模式和末行模式:启动vim进入的是命令模式(也称为Normal模式),在命令模式下输入英文字母`i`会进入编辑模式(Insert模式),屏幕下方出现`-- INSERT --`提示;在编辑模式下按下`Esc`会回到命令模式,此时如果输入英文`:`会进入末行模式,在末行模式下输入`q!`可以在不保存当前工作的情况下强行退出vim;在命令模式下输入`v`会进入可视模式(Visual模式),可以用光标选择一个区域再完成对应的操作。
......@@ -1017,14 +1017,14 @@ Linux系统的命令通常都是如下所示的格式:
- 比较多个文件。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# vim -d foo.txt bar.txt
[root ~]# vim -d foo.txt bar.txt
```
![](./res/vim-diff.png)
- 打开多个文件。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# vim foo.txt bar.txt hello.txt
[root ~]# vim foo.txt bar.txt hello.txt
```
启动vim后只有一个窗口显示的是foo.txt,可以在末行模式中输入`ls`查看到打开的三个文件,也可以在末行模式中输入`b <num>`来显示另一个文件,例如可以用`:b 2`将bar.txt显示出来,可以用`:b 3`将hello.txt显示出来。
......@@ -1080,7 +1080,7 @@ Linux系统的命令通常都是如下所示的格式:
下面以Nginx为例,演示如何使用yum安装软件。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# yum -y install nginx
[root ~]# yum -y install nginx
...
Installed:
nginx.x86_64 1:1.12.2-2.el7
......@@ -1093,7 +1093,7 @@ Dependency Installed:
nginx-mod-mail.x86_64 1:1.12.2-2.el7
nginx-mod-stream.x86_64 1:1.12.2-2.el7
Complete!
[root@iZwz97tbgo9lkabnat2lo8Z ~]# yum info nginx
[root ~]# yum info nginx
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Installed Packages
......@@ -1111,33 +1111,33 @@ License : BSD
Description : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
: IMAP protocols, with a strong focus on high concurrency, performance and low
: memory usage.
[root@iZwz97tbgo9lkabnat2lo8Z ~]# nginx -v
[root ~]# nginx -v
nginx version: nginx/1.12.2
```
移除Nginx。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# yum -y remove nginx
[root ~]# yum -y remove nginx
```
下面以MySQL为例,演示如何使用rpm安装软件。要安装MySQL需要先到[MySQL官方网站](https://www.mysql.com/)下载对应的[RPM文件](https://dev.mysql.com/downloads/mysql/),当然要选择和你使用的Linux系统对应的版本。MySQL现在是Oracle公司旗下的产品,在MySQL被收购后,MySQL的作者重新制作了一个MySQL的分支MariaDB,可以通过yum进行安装。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z mysql]# ls
[root mysql]# ls
mysql-community-client-5.7.22-1.el7.x86_64.rpm
mysql-community-common-5.7.22-1.el7.x86_64.rpm
mysql-community-libs-5.7.22-1.el7.x86_64.rpm
mysql-community-server-5.7.22-1.el7.x86_64.rpm
[root@iZwz97tbgo9lkabnat2lo8Z mysql]# yum -y remove mariadb-libs
[root@iZwz97tbgo9lkabnat2lo8Z mysql]# yum -y install libaio
[root@iZwz97tbgo9lkabnat2lo8Z mysql]#rpm -ivh mysql-community-common-5.7.26-1.el7.x86_64.rpm
[root mysql]# yum -y remove mariadb-libs
[root mysql]# yum -y install libaio
[root mysql]#rpm -ivh mysql-community-common-5.7.26-1.el7.x86_64.rpm
...
[root@iZwz97tbgo9lkabnat2lo8Z mysql]#rpm -ivh mysql-community-libs-5.7.26-1.el7.x86_64.rpm
[root mysql]#rpm -ivh mysql-community-libs-5.7.26-1.el7.x86_64.rpm
...
[root@iZwz97tbgo9lkabnat2lo8Z mysql]#rpm -ivh mysql-community-client-5.7.26-1.el7.x86_64.rpm
[root mysql]#rpm -ivh mysql-community-client-5.7.26-1.el7.x86_64.rpm
...
[root@iZwz97tbgo9lkabnat2lo8Z mysql]#rpm -ivh mysql-community-server-5.7.26-1.el7.x86_64.rpm
[root mysql]#rpm -ivh mysql-community-server-5.7.26-1.el7.x86_64.rpm
...
```
......@@ -1146,7 +1146,7 @@ mysql-community-server-5.7.22-1.el7.x86_64.rpm
移除安装的MySQL。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# rpm -qa | grep mysql | xargs rpm -e
[root ~]# rpm -qa | grep mysql | xargs rpm -e
```
#### 下载解压配置环境变量
......@@ -1154,7 +1154,7 @@ mysql-community-server-5.7.22-1.el7.x86_64.rpm
下面以安装MongoDB为例,演示这类软件应该如何安装。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.5.tgz
[root ~]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.5.tgz
--2018-06-21 18:32:53-- https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.5.tgz
Resolving fastdl.mongodb.org (fastdl.mongodb.org)... 52.85.83.16, 52.85.83.228, 52.85.83.186, ...
Connecting to fastdl.mongodb.org (fastdl.mongodb.org)|52.85.83.16|:443... connected.
......@@ -1163,8 +1163,8 @@ Length: 100564462 (96M) [application/x-gzip]
Saving to: ‘mongodb-linux-x86_64-rhel70-3.6.5.tgz’
100%[==================================================>] 100,564,462 630KB/s in 2m 9s
2018-06-21 18:35:04 (760 KB/s) - ‘mongodb-linux-x86_64-rhel70-3.6.5.tgz’ saved [100564462/100564462]
[root@iZwz97tbgo9lkabnat2lo8Z ~]# gunzip mongodb-linux-x86_64-rhel70-3.6.5.tgz
[root@iZwz97tbgo9lkabnat2lo8Z ~]# tar -xvf mongodb-linux-x86_64-rhel70-3.6.5.tar
[root ~]# gunzip mongodb-linux-x86_64-rhel70-3.6.5.tgz
[root ~]# tar -xvf mongodb-linux-x86_64-rhel70-3.6.5.tar
mongodb-linux-x86_64-rhel70-3.6.5/README
mongodb-linux-x86_64-rhel70-3.6.5/THIRD-PARTY-NOTICES
mongodb-linux-x86_64-rhel70-3.6.5/MPL-2
......@@ -1183,13 +1183,13 @@ mongodb-linux-x86_64-rhel70-3.6.5/bin/mongod
mongodb-linux-x86_64-rhel70-3.6.5/bin/mongos
mongodb-linux-x86_64-rhel70-3.6.5/bin/mongo
mongodb-linux-x86_64-rhel70-3.6.5/bin/install_compass
[root@iZwz97tbgo9lkabnat2lo8Z ~]# vim .bash_profile
[root ~]# vim .bash_profile
...
PATH=$PATH:$HOME/bin:$HOME/mongodb-linux-x86_64-rhel70-3.6.5/bin
export PATH
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# source .bash_profile
[root@iZwz97tbgo9lkabnat2lo8Z ~]# mongod --version
[root ~]# source .bash_profile
[root ~]# mongod --version
db version v3.6.5
git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
......@@ -1199,7 +1199,7 @@ build environment:
distmod: rhel70
distarch: x86_64
target_arch: x86_64
[root@iZwz97tbgo9lkabnat2lo8Z ~]# mongo --version
[root ~]# mongo --version
MongoDB shell version v3.6.5
git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
......@@ -1218,20 +1218,20 @@ build environment:
1. 安装Python 3.6。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# yum install gcc
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz
[root@iZwz97tbgo9lkabnat2lo8Z ~]# gunzip Python-3.6.5.tgz
[root@iZwz97tbgo9lkabnat2lo8Z ~]# tar -xvf Python-3.6.5.tar
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cd Python-3.6.5
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ./configure --prefix=/usr/local/python36 --enable-optimizations
[root@iZwz97tbgo9lkabnat2lo8Z ~]# yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
[root@iZwz97tbgo9lkabnat2lo8Z ~]# make && make install
[root ~]# yum install gcc
[root ~]# wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz
[root ~]# gunzip Python-3.6.5.tgz
[root ~]# tar -xvf Python-3.6.5.tar
[root ~]# cd Python-3.6.5
[root ~]# ./configure --prefix=/usr/local/python36 --enable-optimizations
[root ~]# yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
[root ~]# make && make install
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ln -s /usr/local/python36/bin/python3.6 /usr/bin/python3
[root@iZwz97tbgo9lkabnat2lo8Z ~]# python3 --version
[root ~]# ln -s /usr/local/python36/bin/python3.6 /usr/bin/python3
[root ~]# python3 --version
Python 3.6.5
[root@iZwz97tbgo9lkabnat2lo8Z ~]# python3 -m pip install -U pip
[root@iZwz97tbgo9lkabnat2lo8Z ~]# pip3 --version
[root ~]# python3 -m pip install -U pip
[root ~]# pip3 --version
```
> 说明:上面在安装好Python之后还需要注册PATH环境变量,将Python安装路径下bin文件夹的绝对路径注册到PATH环境变量中。注册环境变量可以修改用户主目录下的.bash_profile或者/etc目录下的profile文件,二者的区别在于前者相当于是用户环境变量,而后者相当于是系统环境变量。
......@@ -1239,14 +1239,14 @@ build environment:
2. 安装Redis-3.2.12。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
[root@iZwz97tbgo9lkabnat2lo8Z ~]# gunzip redis-3.2.12.tar.gz
[root@iZwz97tbgo9lkabnat2lo8Z ~]# tar -xvf redis-3.2.12.tar
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cd redis-3.2.12
[root@iZwz97tbgo9lkabnat2lo8Z ~]# make && make install
[root@iZwz97tbgo9lkabnat2lo8Z ~]# redis-server --version
[root ~]# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
[root ~]# gunzip redis-3.2.12.tar.gz
[root ~]# tar -xvf redis-3.2.12.tar
[root ~]# cd redis-3.2.12
[root ~]# make && make install
[root ~]# redis-server --version
Redis server v=3.2.12 sha=00000000:0 malloc=jemalloc-4.0.3 bits=64 build=5bc5cd3c03d6ceb6
[root@iZwz97tbgo9lkabnat2lo8Z ~]# redis-cli --version
[root ~]# redis-cli --version
redis-cli 3.2.12
```
......@@ -1257,34 +1257,34 @@ build environment:
1. 启动防火墙服务。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl start firewalld
[root ~]# systemctl start firewalld
```
2. 终止防火墙服务。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl stop firewalld
[root ~]# systemctl stop firewalld
```
3. 重启防火墙服务。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl restart firewalld
[root ~]# systemctl restart firewalld
```
4. 查看防火墙服务状态。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl status firewalld
[root ~]# systemctl status firewalld
```
5. 设置/禁用防火墙服务开机自启。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl enable firewalld
[root ~]# systemctl enable firewalld
Created symlink from /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service to /usr/lib/systemd/system/firewalld.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/firewalld.service to /usr/lib/systemd/system/firewalld.service.
[root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl disable firewalld
[root ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
```
......@@ -1300,7 +1300,7 @@ build environment:
指定3天以后下午5点要执行的任务。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ at 5pm+3days
[root ~]# at 5pm+3days
at> rm -f /root/*.html
at> <EOT>
job 9 at Wed Jun 5 17:00:00 2019
......@@ -1309,30 +1309,30 @@ build environment:
查看待执行的任务队列。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ atq
9 Wed Jun 5 17:00:00 2019 a hellokitty
[root ~]# atq
9 Wed Jun 5 17:00:00 2019 a root
```
从队列中删除指定的任务。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ atrm 9
[root ~]$ atrm 9
```
2. 计划任务表 - **crontab**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# crontab -e
[root ~]# crontab -e
* * * * * echo "hello, world!" >> /root/hello.txt
59 23 * * * rm -f /root/*.log
```
> 说明:输入`crontab -e`命令会打开vim来编辑Cron表达式并指定触发的任务,上面我们定制了两个计划任务,一个是每分钟向/root目录下的hello.txt中追加输出`hello, world!`;另一个是每天23时59分执行删除/root目录下以log为后缀名的文件。如果不知道Cron表达式如何书写,可以参照/etc/crontab文件中的提示(下面会讲到)或者用谷歌搜索一下,也可以使用Cron表达式在线生成器来生成Cron表达式。
> 说明:输入`crontab -e`命令会打开vim来编辑Cron表达式并指定触发的任务,上面我们定制了两个计划任务,一个是每分钟向/root目录下的hello.txt中追加输出`hello, world!`;另一个是每天23时59分执行删除/root目录下以log为后缀名的文件。如果不知道Cron表达式如何书写,可以参照/etc/crontab文件中的提示(下面会讲到)或者用搜索引擎找一下“Cron表达式在线生成器”来生成Cron表达式。
和crontab相关的文件在`/etc`目录下,通过修改`/etc`目录下的crontab文件也能够定制计划任务。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cd /etc
[root@iZwz97tbgo9lkabnat2lo8Z etc]# ls -l | grep cron
[root ~]# cd /etc
[root etc]# ls -l | grep cron
-rw-------. 1 root root 541 Aug 3 2017 anacrontab
drwxr-xr-x. 2 root root 4096 Mar 27 11:56 cron.d
drwxr-xr-x. 2 root root 4096 Mar 27 11:51 cron.daily
......@@ -1341,7 +1341,7 @@ build environment:
drwxr-xr-x. 2 root root 4096 Jun 10 2014 cron.monthly
-rw-r--r-- 1 root root 493 Jun 23 15:09 crontab
drwxr-xr-x. 2 root root 4096 Jun 10 2014 cron.weekly
[root@iZwz97tbgo9lkabnat2lo8Z etc]# vim crontab
[root etc]# vim crontab
1 SHELL=/bin/bash
2 PATH=/sbin:/bin:/usr/sbin:/usr/bin
3 MAILTO=root
......@@ -1364,13 +1364,13 @@ build environment:
1. 安全远程连接 - **ssh**。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ ssh root@120.77.222.217
The authenticity of host '120.77.222.217 (120.77.222.217)' can't be established.
ECDSA key fingerprint is SHA256:BhUhykv+FvnIL03I9cLRpWpaCxI91m9n7zBWrcXRa8w.
ECDSA key fingerprint is MD5:cc:85:e9:f0:d7:07:1a:26:41:92:77:6b:7f:a0:92:65.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '120.77.222.217' (ECDSA) to the list of known hosts.
root@120.77.222.217's password:
[root ~]$ ssh root@120.77.222.217
The authenticity of host '120.77.222.217 (120.77.222.217)' can't be established.
ECDSA key fingerprint is SHA256:BhUhykv+FvnIL03I9cLRpWpaCxI91m9n7zBWrcXRa8w.
ECDSA key fingerprint is MD5:cc:85:e9:f0:d7:07:1a:26:41:92:77:6b:7f:a0:92:65.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '120.77.222.217' (ECDSA) to the list of known hosts.
root@120.77.222.217's password:
```
2. 通过网络获取资源 - **wget**。
......@@ -1384,7 +1384,7 @@ build environment:
4. 网络配置工具(旧) - **ifconfig**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ifconfig eth0
[root ~]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.61.250 netmask 255.255.240.0 broadcast 172.18.63.255
ether 00:16:3e:02:b6:46 txqueuelen 1000 (Ethernet)
......@@ -1397,7 +1397,7 @@ build environment:
5. 网络配置工具(新) - **ip**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ip address
[root ~]# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
......@@ -1411,7 +1411,7 @@ build environment:
6. 网络可达性检查 - **ping**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ping www.baidu.com -c 3
[root ~]# ping www.baidu.com -c 3
PING www.a.shifen.com (220.181.111.188) 56(84) bytes of data.
64 bytes from 220.181.111.188 (220.181.111.188): icmp_seq=1 ttl=51 time=36.3 ms
64 bytes from 220.181.111.188 (220.181.111.188): icmp_seq=2 ttl=51 time=36.4 ms
......@@ -1426,16 +1426,16 @@ build environment:
8. 查看网络服务和端口 - **netstat** / **ss**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# netstat -nap | grep nginx
[root ~]# netstat -nap | grep nginx
```
9. 网络监听抓包 - **tcpdump**。
10. 安全文件拷贝 - **scp**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# scp root@1.2.3.4:/root/guido.jpg hellokitty@4.3.2.1:/home/hellokitty/pic.jpg
```
```Shell
[root ~]# scp root@1.2.3.4:/root/guido.jpg hellokitty@4.3.2.1:/home/hellokitty/pic.jpg
```
11. 文件同步工具 - **rsync**。
......@@ -1444,9 +1444,9 @@ build environment:
12. 安全文件传输 - **sftp**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# sftp root@120.77.222.217
root@120.77.222.217's password:
Connected to 120.77.222.217.
[root ~]# sftp root@1.2.3.4
root@1.2.3.4's password:
Connected to 1.2.3.4.
sftp>
```
......@@ -1473,12 +1473,12 @@ build environment:
1. 查看进程 - **ps**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ps -ef
[root ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jun23 ? 00:00:05 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
root 2 0 0 Jun23 ? 00:00:00 [kthreadd]
...
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ps -ef | grep mysqld
[root ~]# ps -ef | grep mysqld
root 4943 4581 0 22:45 pts/0 00:00:00 grep --color=auto mysqld
mysql 25257 1 0 Jun25 ? 00:00:39 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
```
......@@ -1486,7 +1486,7 @@ build environment:
2. 显示进程状态树 - **pstree**。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# pstree
[root ~]# pstree
systemd─┬─AliYunDun───18*[{AliYunDun}]
├─AliYunDunUpdate───3*[{AliYunDunUpdate}]
├─2*[agetty]
......@@ -1512,14 +1512,14 @@ build environment:
3. 查找与指定条件匹配的进程 - **pgrep**。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ pgrep mysqld
[root ~]$ pgrep mysqld
3584
```
4. 通过进程号终止进程 - **kill**。
```Shell
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ kill -l
[root ~]$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
......@@ -1533,8 +1533,8 @@ build environment:
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
[root@iZwz97tbgo9lkabnat2lo8Z ~]# kill 1234
[root@iZwz97tbgo9lkabnat2lo8Z ~]# kill -9 1234
[root ~]# kill 1234
[root ~]# kill -9 1234
```
例子:用一条命令强制终止正在运行的Redis进程。
......@@ -1548,13 +1548,13 @@ build environment:
结束名为mysqld的进程。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# pkill mysqld
[root ~]# pkill mysqld
```
结束hellokitty用户的所有进程。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# pkill -u hellokitty
[root ~]# pkill -u hellokitty
```
> 说明:这样的操作会让hellokitty用户和服务器断开连接。
......@@ -1565,8 +1565,8 @@ build environment:
- `&` - 将进程置于后台运行。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# mongod &
[root@iZwz97tbgo9lkabnat2lo8Z ~]# redis-server
[root ~]# mongod &
[root ~]# redis-server
...
^Z
[4]+ Stopped redis-server
......@@ -1575,7 +1575,7 @@ build environment:
7. 查询后台进程 - **jobs**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# jobs
[root ~]# jobs
[2] Running mongod &
[3]- Stopped cat
[4]+ Stopped redis-server
......@@ -1584,9 +1584,9 @@ build environment:
8. 让进程在后台继续运行 - **bg**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# bg %4
[root ~]# bg %4
[4]+ redis-server &
[root@iZwz97tbgo9lkabnat2lo8Z ~]# jobs
[root ~]# jobs
[2] Running mongod &
[3]+ Stopped cat
[4]- Running redis-server &
......@@ -1595,7 +1595,7 @@ build environment:
9. 将后台进程置于前台 - **fg**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# fg %4
[root ~]# fg %4
redis-server
```
......@@ -1606,15 +1606,15 @@ build environment:
11. 用户登出后进程继续工作 - **nohup**。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# nohup ping www.baidu.com > result.txt &
[root ~]# nohup ping www.baidu.com > result.txt &
```
12. 跟踪进程系统调用情况 - **strace**。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# pgrep mysqld
[root ~]# pgrep mysqld
8803
[root@izwz97tbgo9lkabnat2lo8z ~]# strace -c -p 8803
[root ~]# strace -c -p 8803
strace: Process 8803 attached
^Cstrace: Process 8803 detached
% time seconds usecs/call calls errors syscall
......@@ -1633,14 +1633,14 @@ build environment:
13. 查看当前运行级别 - **runlevel**。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# runlevel
[root ~]# runlevel
N 3
```
14. 实时监控进程占用资源状况 - **top**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# top
[root ~]# top
top - 23:04:23 up 3 days, 14:10, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 65 total, 1 running, 64 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
......@@ -1661,7 +1661,7 @@ build environment:
2. 查看系统活动信息 - **sar**。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# sar -u -r 5 10
[root ~]# sar -u -r 5 10
Linux 3.10.0-957.10.1.el7.x86_64 (izwz97tbgo9lkabnat2lo8z) 06/02/2019 _x86_64_ (2 CPU)
06:48:30 PM CPU %user %nice %system %iowait %steal %idle
......@@ -1680,7 +1680,7 @@ build environment:
3. 查看内存使用情况 - **free**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# free
[root ~]# free
total used free shared buff/cache available
Mem: 1016168 323924 190452 356 501792 531800
Swap: 0 0 0
......@@ -1689,7 +1689,7 @@ build environment:
4. 虚拟内存统计 - **vmstat**。
```Shell
[root@iZ8vba0s66jjlfmo601w4xZ ~]# vmstat
[root ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 204020 79036 667532 0 0 5 18 101 58 1 0 99 0 0
......@@ -1698,7 +1698,7 @@ build environment:
5. CPU信息统计 - **mpstat**。
```Shell
[root@iZ8vba0s66jjlfmo601w4xZ ~]# mpstat
[root ~]# mpstat
Linux 3.10.0-957.5.1.el7.x86_64 (iZ8vba0s66jjlfmo601w4xZ) 05/30/2019 _x86_64_ (1 CPU)
01:51:54 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
......@@ -1708,11 +1708,11 @@ build environment:
6. 查看进程使用内存状况 - **pmap**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# ps
[root ~]# ps
PID TTY TIME CMD
4581 pts/0 00:00:00 bash
5664 pts/0 00:00:00 ps
[root@iZwz97tbgo9lkabnat2lo8Z ~]# pmap 4581
[root ~]# pmap 4581
4581: -bash
0000000000400000 884K r-x-- bash
00000000006dc000 4K r---- bash
......@@ -1727,7 +1727,7 @@ build environment:
7. 报告设备CPU和I/O统计信息 - **iostat**。
```Shell
[root@iZwz97tbgo9lkabnat2lo8Z ~]# iostat
[root ~]# iostat
Linux 3.10.0-693.11.1.el7.x86_64 (iZwz97tbgo9lkabnat2lo8Z) 06/26/2018 _x86_64_ (1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.79 0.00 0.20 0.04 0.00 98.97
......@@ -1739,7 +1739,7 @@ build environment:
8. 显示所有PCI设备 - **lspci**。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# lspci
[root ~]# lspci
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
......@@ -1756,7 +1756,7 @@ build environment:
9. 显示进程间通信设施的状态 - **ipcs**。
```Shell
[root@iZ8vba0s66jjlfmo601w4xZ ~]# ipcs
[root ~]# ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
......
......@@ -498,7 +498,7 @@ python3
```Python
>>> from pymongo import MongoClient
>>> client = MongoClient('mongodb://120.77.222.217:27017')
>>> client = MongoClient('mongodb://127.0.0.1:27017')
>>> db = client.school
>>> for student in db.students.find():
... print('学号:', student['stuid'])
......
......@@ -23,7 +23,7 @@ Web开发的早期阶段,开发者需要手动编写每个页面,例如一
#### HTTP协议
这里我们稍微费一些笔墨来谈谈上面提到的HTTP。HTTP(超文本传输协议)是构建于TCP(传输控制协议)之上应用级协议,它利用了TCP提供的可靠的传输服务实现了Web应用中的数据交换。按照维基百科上的介绍,设计HTTP最初的目的是为了提供一种发布和接收[HTML](https://zh.wikipedia.org/wiki/HTML)页面的方法,也就是说这个协议是浏览器和Web服务器之间传输的数据的载体。关于这个协议的详细信息以及目前的发展状况,大家可以阅读阮一峰老师的[《HTTP 协议入门》](http://www.ruanyifeng.com/blog/2016/08/http.html)[《互联网协议入门》](http://www.ruanyifeng.com/blog/2012/05/internet_protocol_suite_part_i.html)系列以及[《图解HTTPS协议》](http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html)进行了解。下图是我于2009年9月10日凌晨4点在四川省网络通信技术重点实验室用开源协议分析工具Ethereal(抓包工具WireShark的前身)截取的访问百度首页时的HTTP请求和响应的报文(协议数据),由于Ethereal截取的是经过网络适配器的数据,因此可以清晰的看到从物理链路层到应用层的协议数据。
这里我们稍微费一些笔墨来谈谈上面提到的HTTP。HTTP(超文本传输协议)是构建于TCP(传输控制协议)之上应用级协议,它利用了TCP提供的可靠的传输服务实现了Web应用中的数据交换。按照维基百科上的介绍,设计HTTP最初的目的是为了提供一种发布和接收[HTML](https://zh.wikipedia.org/wiki/HTML)页面的方法,也就是说这个协议是浏览器和Web服务器之间传输的数据的载体。关于这个协议的详细信息以及目前的发展状况,大家可以阅读阮一峰老师的[《HTTP 协议入门》](http://www.ruanyifeng.com/blog/2016/08/http.html)[《互联网协议入门》](http://www.ruanyifeng.com/blog/2012/05/internet_protocol_suite_part_i.html)系列以及[《图解HTTPS协议》](http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html)进行了解。下图是我在四川省网络通信技术重点实验室学习和工作期间使用开源协议分析工具Ethereal(抓包工具WireShark的前身)截取的访问百度首页时的HTTP请求和响应的报文(协议数据),由于Ethereal截取的是经过网络适配器的数据,因此可以清晰的看到从物理链路层到应用层的协议数据。
HTTP请求(请求行+请求头+空行+[消息体]):
......@@ -33,7 +33,7 @@ HTTP响应(响应行+响应头+空行+消息体):
![](./res/http-response.png)
> 说明:但愿这两张如同泛黄的照片般的截图能帮助你了解HTTP到底是什么样子的。
> 说明:这两张图是在2009年9月10日截取的,但愿这两张如同泛黄的照片般的截图能帮助你了解HTTP到底是什么样子的。
### Django概述
......@@ -51,6 +51,8 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
1. 检查Python环境:Django 1.11需要Python 2.7或Python 3.4以上的版本;Django 2.0需要Python 3.4以上的版本;Django 2.1需要Python 3.5以上的版本。
> 说明:我自己平时使用macOS做开发,macOS和Linux平台使用的命令跟Windows平台有较大的区别,这一点在之前也有过类似的说明,如果使用Windows平台做开发,替换一下对应的命令即可。
```Shell
$ python3 --version
```
......@@ -75,7 +77,7 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
$ python3 -m venv venv
$ source venv/bin/activate
```
> 说明:上面使用了Python自带的venv模块完成了虚拟环境的创建,当然也可以使用其他的工具,例如:virtualenv或pipenv等。要激活虚拟环境,在Windows系统下是通过"venv/Scripts/activate"`执行批处理文件来实现。
> 说明:上面使用了Python自带的venv模块完成了虚拟环境的创建,当然也可以使用virtualenv或pipenv这样的工具。要激活虚拟环境,在Windows环境下可以通过"venv/Scripts/activate"执行批处理文件来实现。
4. 更新包管理工具pip。
......@@ -99,7 +101,7 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
或指定版本号来安装对应的Django的版本。
```Shell
(venv)$ pip install django==1.11
(venv)$ pip install django==2.1.8
```
6. 检查Django的版本。
......@@ -123,7 +125,7 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
(venv)$ pip list
```
下图展示了Django版本和Python版本的对应关系,如果在安装时没有指定版本号,将自动选择最新的版本(在写作这段内容时,最新的版本是2.0;目前最新的版本已经更新到2.2)。
下图展示了Django版本和Python版本的对应关系,如果在安装时没有指定版本号,将自动选择最新的版本(在写作这段内容时,Django最新的版本是2.2)。
| Django版本 | Python版本 |
| ---------- | ----------------------- |
......@@ -143,11 +145,13 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
执行上面的命令后看看生成的文件和文件夹,它们的作用如下所示:
- `manage.py`: 一个让你用各种方式管理 Django 项目的命令行工具。
- `oa/__init__.py`:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。
- `oa/settings.py`:Django 项目的配置文件。
- `oa/urls.py`:Django 项目的 URL 声明,就像你网站的“目录”。
- `oa/wsgi.py`:作为你的项目的运行在 WSGI 兼容的Web服务器上的入口。
- `manage.py`: 一个让你可以管理Django项目的工具程序。
- `oa/__init__.py`:一个空文件,告诉Python解释器这个目录应该被视为一个Python的包。
- `oa/settings.py`:Django项目的配置文件。
- `oa/urls.py`:Django项目的URL声明(URL映射),就像是你的网站的“目录”。
- `oa/wsgi.py`:项目运行在WSGI兼容Web服务器上的接口文件。
> 说明:WSGI全称是Web服务器网关接口,维基百科上给出的解释是“为Python语言定义的[Web服务器](https://zh.wikipedia.org/wiki/%E7%B6%B2%E9%A0%81%E4%BC%BA%E6%9C%8D%E5%99%A8)和[Web应用程序](https://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F)或框架之间的一种简单而通用的接口”。
8. 启动服务器运行项目。
......@@ -164,7 +168,7 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
> 说明2:用于开发的服务器在需要的情况下会对每一次的访问请求重新载入一遍Python代码。所以你不需要为了让修改的代码生效而频繁的重新启动服务器。然而,一些动作,比如添加新文件,将不会触发自动重新加载,这时你得自己手动重启服务器。
> 说明3:可以通过`python manage.py help`命令查看可用命令列表;在启动服务器时,也可以通过`python manage.py runserver 1.2.3.4:5678`来指定绑定的IP地址和端口。
> 说明3:可以通过`python manage.py help`命令查看可用命令列表;在启动服务器时,也可以通过`python manage.py runserver 1.2.3.4:5678`来指定将服务器运行于哪个IP地址和端口。
> 说明4:可以通过Ctrl+C来终止服务器的运行。
......@@ -199,14 +203,14 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
执行上面的命令会在当前路径下创建hrs目录,其目录结构如下所示:
- `__init__.py`:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。
- `__init__.py`:一个空文件,告诉Python解释器这个目录应该被视为一个Python的包。
- `admin.py`:可以用来注册模型,用于在Django的管理界面管理模型。
- `apps.py`:当前应用的配置。
- `apps.py`:当前应用的配置文件
- `migrations`:存放与模型有关的数据库迁移信息。
- `__init__.py`:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。
- `models.py`:存放应用的数据模型,即实体类及其之间的关系(MVC/MVT中的M)。
- `__init__.py`:一个空文件,告诉Python解释器这个目录应该被视为一个Python的包。
- `models.py`:存放应用的数据模型,即实体类及其之间的关系(MVC/MTV中的M)。
- `tests.py`:包含测试应用各项功能的测试类和测试函数。
- `views.py`:处理请求并返回响应的函数(MVC中的C,MVT中的V)。
- `views.py`:处理请求并返回响应的函数(MVC中的C,MTV中的V)。
2. 修改应用目录下的视图文件views.py。
......@@ -240,7 +244,7 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
```
> 说明:上面使用的`path`函数是Django 2.x中新添加的函数,除此之外还可以使用支持正则表达式的URL映射函数`re_path`函数;Django 1.x中是用名为`url`函数来设定URL映射。
4. 切换到项目目录,修改该目录下的urls.py文件,对应用中设定的URL进行合并。
4. 修改项目目录下的urls.py文件,对应用中设定的URL进行合并。
```Shell
(venv) $ vim oa/urls.py
......@@ -256,6 +260,8 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
]
```
> 说明:上面的代码通过`include`函数将hrs应用中配置URL的文件包含到项目的URL配置中,并映射到`hrs/`路径下。
5. 重新运行项目,并打开浏览器中访问<http://localhost:8000/hrs>
```Shell
......@@ -316,9 +322,7 @@ Django诞生于2003年,它是一个在真正的应用中成长起来的项目
上面通过拼接HTML代码的方式生成动态视图的做法在实际开发中是无能接受的,这一点大家一定能够想到。为了解决这个问题,我们可以提前准备一个模板页,所谓模板页就是一个带占位符的HTML页面,当我们将程序中获得的数据替换掉页面中的占位符时,一个动态页面就产生了。
我们可以用Django框架中template模块的Template类创建模板对象,通过模板对象的render方法实现对模板的渲染。所谓的渲染就是用数据替换掉模板页中的占位符,当然这里的渲染称为后端渲染,即在服务器端完成页面的渲染再输出到浏览器中,这种做法的主要坏处是当并发访问量较大时,服务器会承受较大的负担,所以今天有很多的Web应用都使用了前端渲染,即服务器只为浏览器提供所需的数据(通常是JSON格式),在浏览器中通过JavaScript获取这些数据并渲染到页面上,这些内容在后面为大家呈现。
Django框架通过shortcuts模块的快捷函数`render`简化了渲染模板的操作,具体的用法如下所示。
我们可以用Django框架中template模块的Template类创建模板对象,通过模板对象的render方法实现对模板的渲染,在Django框架中还有一个名为`render`的便捷函数可以来完成渲染模板的操作。所谓的渲染就是用数据替换掉模板页中的占位符,当然这里的渲染称为后端渲染,即在服务器端完成页面的渲染再输出到浏览器中,这种做法的主要坏处是当并发访问量较大时,服务器会承受较大的负担,所以今天有很多的Web应用都使用了前端渲染,即服务器只提供所需的数据(通常是JSON格式),在浏览器中通过JavaScript获取这些数据并渲染到页面上,这个我们在后面的内容中会讲到。
1. 先回到manage.py文件所在的目录创建名为templates文件夹。
......@@ -359,7 +363,7 @@ Django框架通过shortcuts模块的快捷函数`render`简化了渲染模板的
</body>
</html>
```
在上面的模板页中我们使用了`{{ greeting }}`这样的模板占位符语法,也使用了`{% for %}`这样的模板指令,这些都是Django模板语言(DTL)的一部分。如果对此不熟悉并不要紧,我们会在后续的内容中进一步的讲解,而且我们刚才也说到了,还有更好的选择就是使用前端渲染,当然这是后话。
在上面的模板页中我们使用了`{{ greeting }}`这样的模板占位符语法,也使用了`{% for %}`这样的模板指令,这些都是Django模板语言(DTL)的一部分。如果对此不熟悉并不要紧,我们会在后续的内容中进一步的讲解,而且我们刚才也说到了,渲染页面还有更好的选择就是使用前端渲染,当然这是后话。
3. 回到应用目录,修改views.py文件。
......@@ -381,6 +385,8 @@ Django框架通过shortcuts模块的快捷函数`render`简化了渲染模板的
return render(request, 'index.html', {'depts_list': depts_list})
```
> 说明:Django框架通过shortcuts模块的便捷函数`render`简化了渲染模板的操作,有了这个函数,就不用先创建`Template`对象再去调用`render`方法。。
到此为止,我们还没有办法让views.py中的`render`函数找到模板文件index.html,为此我们需要修改settings.py文件,配置模板文件所在的路径。
4. 切换到项目目录修改settings.py文件。
......@@ -420,6 +426,5 @@ Django框架通过shortcuts模块的快捷函数`render`简化了渲染模板的
### 总结
至此,我们已经利用Django框架完成了一个非常小的Web应用,虽然它并没有任何的实际价值,但是可以通过这个项目对Django框架有一个感性的认识。当然,实际开发中我们可以用PyCharm来创建项目,如果使用专业版的PyCharm,可以直接创建Django项目。使用PyCharm的好处在于编写代码时可以获得代码提示、错误修复、自动导入等功能,从而提升开发效率,但是专业版的PyCharm需要按年支付相应的费用,社区版的PyCharm中并未包含对Django框架直接的支持,但是我们仍然可以使用它来创建Django项目,只是在使用上没有专业版的方便。关于PyCharm的使用,可以参考[《玩转PyCharm》](../玩转PyCharm.md)一文。
至此,我们已经利用Django框架完成了一个非常小的Web应用,虽然它并没有任何的实际价值,但是可以通过这个项目对Django框架有一个感性的认识。当然,实际开发中我们可以用PyCharm来创建项目,如果使用专业版的PyCharm,可以直接创建Django项目。使用PyCharm的好处在于编写代码时可以获得代码提示、错误修复、自动导入等功能,从而提升开发效率,但是专业版的PyCharm需要按年支付相应的费用,社区版的PyCharm中并未包含对Django框架直接的支持,但是我们仍然可以使用它来创建Django项目,只是在使用上没有专业版的方便。关于PyCharm的使用,可以参考[《玩转PyCharm》](../玩转PyCharm.md)一文。此外,Django最好的学习资料肯定是它的[官方文档](https://docs.djangoproject.com/zh-hans/2.0/),当然图灵社区出版的[《Django基础教程》](http://www.ituring.com.cn/book/2630)也是非常适合初学者的入门级读物。
此外,学习Django最好的资料肯定是它的[官方文档](https://docs.djangoproject.com/zh-hans/2.0/),除此之外图灵社区出版的[《Django基础教程》](http://www.ituring.com.cn/book/2630)也是非常适合初学者的读物。
\ No newline at end of file
## 深入模型
在上一个章节中,我们提到了Django是基于MVC架构的Web框架,MVC架构追求的是“模型”和“视图”的解耦合。所谓“模型”说得更直白一些就是数据,所以通常也被称作“数据模型”。在实际的项目中,数据模型通常通过数据库实现持久化操作,而关系型数据库在很长一段时间都是持久化的首选方案,下面我们以MySQL为例来说明如何使用关系型数据库来实现持久化操作。
在上一个章节中,我们提到了Django是基于MVC架构的Web框架,MVC架构追求的是“模型”和“视图”的解耦合。所谓“模型”说得更直白一些就是数据(的表示),所以通常也被称作“数据模型”。在实际的项目中,数据模型通常通过数据库实现持久化操作,而关系型数据库在过去和当下都是持久化的首选方案,下面我们以MySQL为例来说明如何使用关系型数据库来实现持久化操作。
### 配置关系型数据库MySQL
......@@ -9,7 +9,7 @@
1. 修改项目的settings.py文件,首先将我们之前创建的应用hrs添加已安装的项目中,然后配置MySQL作为持久化方案。
```Shell
(venv)$ cd oa/settings.py
(venv)$ vim oa/settings.py
```
```Python
......@@ -29,7 +29,7 @@
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'oa',
'HOST': 'localhost',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '123456',
......@@ -50,13 +50,13 @@
NAME属性代表数据库的名称,如果使用SQLite它对应着一个文件,在这种情况下NAME的属性值应该是一个绝对路径;使用其他关系型数据库,则要配置对应的HOST(主机)、PORT(端口)、USER(用户名)、PASSWORD(口令)等属性。
2. 安装MySQL客户端工具,Python 3中使用PyMySQL,Python 2中用MySQLdb。
2. 安装Python操作MySQL的依赖库,Python 3中通常使用PyMySQL,Python 2中通常用MySQLdb。
```Shell
(venv)$ pip install pymysql
```
如果使用Python 3需要修改**项目**`__init__.py`文件并加入如下所示的代码,这段代码的作用是将PyMySQL视为MySQLdb来使用,从而避免Django找不到连接MySQL的客户端工具而询问你:“Did you install mysqlclient? ”(你安装了mysqlclient吗?)。
如果使用Python 3需要修改**项目目录**`__init__.py`文件并加入如下所示的代码,这段代码的作用是将PyMySQL视为MySQLdb来使用,从而避免Django找不到连接MySQL的客户端工具而询问你:“Did you install mysqlclient? ”(你安装了mysqlclient吗?)。
```Python
import pymysql
......@@ -64,15 +64,15 @@
pymysql.install_as_MySQLdb()
```
3. 运行manage.py并指定migrate参数实现数据库迁移,为应用程序创建对应的数据表,当然在此之前需要**先启动MySQL数据库服务器并创建名为oa的数据库**,在MySQL中创建数据库的语句如下所示。
3. 如果之前没有为应用程序创建数据库,那么现在是时候创建名为oa的数据库了。在MySQL中创建数据库的SQL语句如下所示:
```SQL
drop database if exists oa;
create database oa default charset utf8;
```
4. Django框架本身有自带的数据模型,我们稍后会用到这些模型,为此我们先做一次迁移操作。所谓迁移,就是根据模型自动生成关系数据库中的二维表,命令如下所示:
```Shell
(venv)$ cd ..
(venv)$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
......@@ -93,7 +93,7 @@
Applying sessions.0001_initial... OK
```
4. 可以看到,Django帮助我们创建了10张表,这些都是使用Django框架需要的东西,稍后我们就会用到这些表。除此之外,我们还应该为我们自己的应用创建数据模型。如果要在hrs应用中实现对部门和员工的管理,我们可以创建如下所示的数据模型
5. 接下来,我们为自己的应用创建数据模型。如果要在hrs应用中实现对部门和员工的管理,我们可以先创建部门和员工数据模型,代码如下所示
```Shell
(venv)$ vim hrs/models.py
......@@ -120,11 +120,11 @@
no = models.IntegerField(primary_key=True, db_column='eno', verbose_name='员工编号')
name = models.CharField(max_length=20, db_column='ename', verbose_name='员工姓名')
job = models.CharField(max_length=10, verbose_name='职位')
# 自参照完整性多对一外键关联
mgr = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='主管编号')
# 多对一外键关联(自参照)
mgr = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='主管')
sal = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='月薪')
comm = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True, verbose_name='补贴')
# 多对一外键关联
# 多对一外键关联(参照部门模型)
dept = models.ForeignKey(Dept, db_column='dno', on_delete=models.PROTECT, verbose_name='所在部门')
class Meta:
......@@ -132,7 +132,7 @@
```
> 说明:上面定义模型时使用了字段类及其属性,其中IntegerField对应数据库中的integer类型,CharField对应数据库的varchar类型,DecimalField对应数据库的decimal类型,ForeignKey用来建立多对一外键关联。字段属性primary_key用于设置主键,max_length用来设置字段的最大长度,db_column用来设置数据库中与字段对应的列,verbose_name则设置了Django后台管理系统中该字段显示的名称。如果对这些东西感到很困惑也不要紧,文末提供了字段类、字段属性、元数据选项等设置的相关说明,不清楚的读者可以稍后查看对应的参考指南。
5. 通过模型创建数据表。
6. 再次执行迁移操作,先通过模型生成迁移文件,再执行迁移创建二维表。
```Shell
(venv)$ python manage.py makemigrations hrs
......@@ -151,7 +151,9 @@
![](./res/er-graph.png)
### 在后台管理模型
### 利用Django后台管理模型
Django框架有自带的后台管理系统来实现对模型的管理。虽然实际应用中,这个后台可能并不能满足我们的需求,但是在学习Django框架时,我们暂时可以利用Django自带的后台管理系统来管理我们的模型,同时也可以了解一个项目的后台管理系统到底需要哪些功能。
1. 创建超级管理员账号。
......@@ -201,23 +203,23 @@
4. 对模型进行CRUD操作。
可以在管理员平台对模型进行C(新增)R(查看)U(更新)D(删除)操作,如下图所示。
可以在管理员平台对模型进行C(新增)、R(查看)、U(更新)、D(删除)操作,如下图所示。
添加新的部门。
- 添加新的部门。
![](./res/admin-model-create.png)
查看所有部门。
- 查看所有部门。
![](./res/admin-model-read.png)
更新和删除部门。
- 更新和删除部门。
![](./res/admin-model-delete-and-update.png)
5. 注册模型管理类。
再次修改admin.py文件,通过注册模型管理类,可以在后台管理系统中更好的管理模型。
可能大家已经注意到了,刚才在后台查看部门信息的时候,显示的部门信息并不直观,为此我们再修改admin.py文件,通过注册模型管理类,可以在后台管理系统中更好的管理模型。
```Python
from django.contrib import admin
......@@ -265,19 +267,12 @@
class Emp(models.Model):
"""员工类"""
# 此处省略上面的代码
mgr = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='直接主管')
# 此处省略下面的代码
# 此处省略上面的代码
def __str__(self):
return self.name
# 此处省略下面的代码
```
修改代码后刷新查看Emp模型的页面,效果如下图所示。
......@@ -301,6 +296,7 @@ Type "help", "copyright", "credits" or "license" for more information.
```Shell
>>> from hrs.models import Dept, Emp
>>>
>>> dept = Dept(40, '研发2部', '深圳')
>>> dept.save()
```
......@@ -314,14 +310,14 @@ Type "help", "copyright", "credits" or "license" for more information.
#### 查询
查询所有对象。
1. 查询所有对象。
```Shell
>>> Dept.objects.all()
<QuerySet [<Dept: 研发1部>, <Dept: 销售1部>, <Dept: 运维1部>, <Dept: 研发3部>]>
```
过滤数据。
2. 过滤数据。
```Shell
>>> Dept.objects.filter(name='研发3部') # 查询部门名称为“研发3部”的部门
......@@ -337,7 +333,7 @@ Type "help", "copyright", "credits" or "license" for more information.
<QuerySet [<Dept: 研发1部>, <Dept: 销售1部>, <Dept: 运维1部>]>
```
查询单个对象。
3. 查询单个对象。
```Shell
>>> Dept.objects.get(pk=10)
......@@ -353,7 +349,7 @@ Type "help", "copyright", "credits" or "license" for more information.
<Dept: 研发1部>
```
排序数据。
4. 排序数据。
```Shell
>>> Dept.objects.order_by('no') # 查询所有部门按部门编号升序排列
......@@ -363,7 +359,7 @@ Type "help", "copyright", "credits" or "license" for more information.
<QuerySet [<Dept: 研发3部>, <Dept: 运维1部>, <Dept: 销售1部>, <Dept: 研发1部>]>
```
切片数据
5. 数据切片(分页查询)
```Shell
>>> Dept.objects.order_by('no')[0:2] # 按部门编号排序查询1~2部门
......@@ -373,7 +369,7 @@ Type "help", "copyright", "credits" or "license" for more information.
<QuerySet [<Dept: 运维1部>, <Dept: 研发3部>]>
```
高级查询。
6. 高级查询。
```Shell
>>> Emp.objects.filter(dept__no=10) # 根据部门编号查询该部门的员工
......
## 静态资源和Ajax请求
基于前面两个章节讲解的知识,我们已经可以使用Django框架来实现Web应用的开发了。接下来我们就尝试实现一个投票应用,具体的需求是用户进入应用首先查看到“学科介绍”页面,该页面显示了一个学校所开设的所有学科;通过点击某个学科,可以进入“老师介绍”页面,该页面展示了该学科所有老师的详细情况,可以在该页面上给老师点击“好评”或“差评”,但是会先跳转到“登录页”要求用户登录,登录成功才能投票;对于未注册的用户,可以在“登录页”点击“新用户注册”进入“注册页”完成用户注册,注册成功后会跳转到“登录页”,注册失败会获得相应的提示信息。
基于前面两个章节讲解的知识,我们已经可以使用Django框架来完成Web应用的开发了。接下来我们就尝试实现一个投票应用,具体的需求是用户进入应用首先查看到“学科介绍”页面,该页面显示了一个学校所开设的所有学科;通过点击某个学科,可以进入“老师介绍”页面,该页面展示了该学科所有老师的详细情况,可以在该页面上给老师点击“好评”或“差评”;如果用户没有登录,在投票时会先跳转到“登录页”要求用户登录,登录成功才能投票;对于未注册的用户,可以在“登录页”点击“新用户注册”进入“注册页”完成用户注册操作,注册成功后会跳转到“登录页”,注册失败会获得相应的提示信息。
### 准备工作
......@@ -53,7 +53,7 @@ class Teacher(models.Model):
...
```
> 注意:为了给vote应用生成迁移,需要先修改Django项目的配置文件settings.py,在INSTALLED_APPS中添加vote应用。
> 注意:为了给vote应用生成迁移文件,需要修改Django项目settings.py文件,在INSTALLED_APPS中添加vote应用。
完成模型迁移之后,我们可以通过下面的SQL语句来添加学科和老师测试的数据。
......@@ -69,10 +69,10 @@ VALUES
INSERT INTO `tb_teacher` (`no`,`name`,`gender`,`birth`,`intro`,`good_count`,`bad_count`,`photo`,`sno`)
VALUES
(1, '骆昊', 1, '1980-11-28', '10年以上软硬件产品设计、研发、架构和管理经验,2003年毕业于四川大学,四川大学Java技术俱乐部创始人,四川省优秀大学毕业生,在四川省网络通信技术重点实验室工作期间,参与了2项国家自然科学基金项目、1项中国科学院中长期研究项目和多项四川省科技攻关项目,在国际会议和国内顶级期刊上发表多篇论文(1篇被SCI收录,3篇被EI收录),大规模网络性能测量系统DMC-TS的设计者和开发者,perf-TTCN语言的发明者。国内最大程序员社区CSDN的博客专家,在Github上参与和维护了多个高质量开源项目,精通C/C++、Java、Python、R、Swift、JavaScript等编程语言,擅长OOAD、系统架构、算法设计、协议分析和网络测量,主持和参与过电子政务系统、KPI考核系统、P2P借贷平台等产品的研发,一直践行“用知识创造快乐”的教学理念,善于总结,乐于分享。', 0, 0, 'images/luohao.png', 1),
(2, '王海飞', 1, '1993-05-24', '5年以上Python开发经验,先后参与了O2O商城、CRM系统、CMS平台、ERP系统等项目的设计与研发,曾在全国最大最专业的汽车领域相关服务网站担任Python高级研发工程师、项目经理等职务,擅长基于Python、Java、PHP等开发语言的企业级应用开发,全程参与了多个企业级应用从需求到上线所涉及的各种工作,精通Django、Flask等框架,熟悉基于微服务的企业级项目开发,拥有丰富的项目实战经验。善于用浅显易懂的方式在课堂上传授知识点,在授课过程中经常穿插企业开发的实际案例并分析其中的重点和难点,通过这种互动性极强的教学模式帮助学员找到解决问题的办法并提升学员的综合素质。', 0, 0, 'images/wangdachui.png', 1),
(2, '王海飞', 1, '1993-05-24', '5年以上Python开发经验,先后参与了O2O商城、CRM系统、CMS平台、ERP系统等项目的设计与研发,曾在全国最大最专业的汽车领域相关服务网站担任Python高级研发工程师、项目经理等职务,擅长基于Python、Java、PHP等开发语言的企业级应用开发,全程参与了多个企业级应用从需求到上线所涉及的各种工作,精通Django、Flask等框架,熟悉基于微服务的企业级项目开发,拥有丰富的项目实战经验。善于用浅显易懂的方式在课堂上传授知识点,在授课过程中经常穿插企业开发的实际案例并分析其中的重点和难点,通过这种互动性极强的教学模式帮助学员找到解决问题的办法并提升学员的综合素质。', 0, 0, 'images/wanghaifei.png', 1),
(3, '余婷', 0, '1992-03-12', '5年以上移动互联网项目开发经验和教学经验,曾担任上市游戏公司高级软件研发工程师和移动端(iOS)技术负责人,参了多个企业级应用和游戏类应用的移动端开发和后台服务器开发,拥有丰富的开发经验和项目管理经验,以个人开发者和协作开发者的身份在苹果的AppStore上发布过多款App。精通Python、C、Objective-C、Swift等开发语言,熟悉iOS原生App开发、RESTful接口设计以及基于Cocos2d-x的游戏开发。授课条理清晰、细致入微,性格活泼开朗、有较强的亲和力,教学过程注重理论和实践的结合,在学员中有良好的口碑。', 0, 0, 'images/yuting.png', 1),
(4, '肖世荣', 1, '1977-07-02', '10年以上互联网和移动互联网产品设计、研发、技术架构和项目管理经验,曾在中国移动、symbio、ajinga.com、万达信息等公司担任架构师、项目经理、技术总监等职务,长期为苹果、保时捷、耐克、沃尔玛等国际客户以及国内的政府机构提供信息化服务,主导的项目曾获得“世界科技先锋”称号,个人作品“许愿吧”曾在腾讯应用市场生活类App排名前3,拥有百万级用户群体,运营的公众号“卵石坊”是国内知名的智能穿戴设备平台。精通Python、C++、Java、Ruby、JavaScript等开发语言,主导和参与了20多个企业级项目(含国家级重大项目和互联网创新项目),涉及的领域包括政务、社交、电信、卫生和金融,有极为丰富的项目实战经验。授课深入浅出、条理清晰,善于调动学员的学习热情并帮助学员理清思路和方法。', 0, 0, 'images/xiaoshirong.png', 1),
(5, '张无忌', 1, '1987-07-07', '出生起便在冰火岛过着原始生活,踏入中土后因中玄冥神掌命危而带病习医,忍受寒毒煎熬七年最后因福缘际会练成“九阳神功”更在之后又练成了“乾坤大挪移”等盖世武功,几乎无敌于天下。 生性随和,宅心仁厚,精通医术和药理。20岁时便凭着盖世神功当上明教教主,率领百万教众及武林群雄反抗蒙古政权元朝的高压统治,最后推翻了元朝。由于擅长乾坤大挪移神功,上课遇到问题就转移话题,属于拉不出屎怪地球没有引力的类型。', 0, 0, 'images/zhangwuji.png', 5),
(5, '张无忌', 1, '1987-07-07', '出生起便在冰火岛过着原始生活,踏入中土后因中玄冥神掌命危而带病习医,忍受寒毒煎熬七年最后因福缘际会练成“九阳神功”更在之后又练成了“乾坤大挪移”等盖世武功,几乎无敌于天下。 生性随和,宅心仁厚,精通医术和药理。20岁时便凭着盖世神功当上明教教主,率领百万教众及武林群雄反抗蒙古政权元朝的高压统治,最后推翻了元朝。由于擅长乾坤大挪移神功,上课遇到问题就转移话题。', 0, 0, 'images/zhangwuji.png', 5),
(6, '韦一笑', 1, '1975-12-15', '外号“青翼蝠王”,为明教四大护教法王之一。 身披青条子白色长袍,轻功十分了得。由于在修炼至阴至寒的“寒冰绵掌”时出了差错,经脉中郁积了至寒阴毒,只要运上内力,寒毒就会发作,如果不吸人血解毒,全身血脉就会凝结成冰,后得张无忌相助,以其高明医术配以“九阳神功”,终将寒毒驱去,摆脱了吸吮人血这一命运。由于轻功绝顶,学生一问问题就跑了。', 0, 0, 'images/weiyixiao.png', 3);
```
......@@ -239,7 +239,7 @@ urlpatterns = [
### Ajax请求
接下来就可以实现“好评”和“差评”的功能了,很明显如果能够在不刷新页面的情况下实现这两个功能会带来更好的用户体验,因此我们考虑使用[Ajax](https://zh.wikipedia.org/wiki/AJAX)技术来实现“好评”和“差评”,Ajax技术我们在之前的章节中已经介绍过了,此处不再赘述。
接下来就可以实现“好评”和“差评”的功能了,很明显如果能够在不刷新页面的情况下实现这两个功能会带来更好的用户体验,因此我们考虑使用[Ajax](https://zh.wikipedia.org/wiki/AJAX)技术来实现“好评”和“差评”,Ajax技术我们在Web前端部分已经介绍过了,此处不再赘述。
首先修改项目的urls.py文件,为“好评”和“差评”功能映射对应的URL。
......@@ -266,7 +266,7 @@ def praise_or_criticize(request):
try:
tno = int(request.GET['tno'])
teacher = Teacher.objects.get(no=tno)
if request.path.startswith('/prise'):
if request.path.startswith('/praise'):
teacher.good_count += 1
else:
teacher.bad_count += 1
......@@ -280,23 +280,60 @@ def praise_or_criticize(request):
修改显示老师信息的模板页,引入jQuery库来实现事件处理、Ajax请求和DOM操作。
```HTML
<script src="{% static 'js/jquery.min.js' %}"></script>
<script>
$(() => {
$('.comment>a').on('click', (evt) => {
evt.preventDefault();
let a = $(evt.target)
let span = a.next()
$.getJSON(a.attr('href'), (json) => {
if (json.code == 200) {
span.text(parseInt(span.text()) + 1)
} else {
alert(json.hint)
}
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>老师信息</title>
<style>/* 此处略去了层叠样式表的选择器 */</style>
</head>
<body>
<h1>{{ subject.name }}的老师信息</h1>
<hr>
<div id="container">
{% for teacher in teachers %}
<div class="teacher">
<div class="photo">
<img src="{% static teacher.photo %}" height="140" alt="">
</div>
<div class="info">
<div>
<span><strong>姓名:{{ teacher.name }}</strong></span>
<span>性别:{{ teacher.gender | yesno:'男,女' }}</span>
<span>出生日期:{{ teacher.birth }}</span>
</div>
<div class="intro">{{ teacher.intro }}</div>
<div class="comment">
<a href="/vote/praise/?tno={{ teacher.no }}">好评</a>
(<span>{{ teacher.good_count }}</span>)
&nbsp;&nbsp;
<a href="/vote/criticize/?tno={{ teacher.no }}">差评</a>
(<span>{{ teacher.bad_count }}</span>)
</div>
</div>
</div>
{% endfor %}
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script>
$(() => {
$('.comment > a').on('click', (evt) => {
evt.preventDefault()
let a = $(evt.target)
$.getJSON(a.attr('href'), (json) => {
if (json.code == 200) {
let span = a.next()
span.text(parseInt(span.text()) + 1)
} else {
alert(json.message)
}
})
})
})
})
</script>
</script>
</body>
</html>
```
### 小结
......
......@@ -20,8 +20,10 @@ class User(models.Model):
通过生成迁移和执行迁移操作,在数据库中创建对应的用户表。
```Shell
python manage.py makemigrations 应用名
python manage.py migrate
(venv)$ python manage.py makemigrations vote
...
(venv)$ python manage.py migrate
...
```
定制一个非常简单的注册模板页面。
......@@ -62,13 +64,13 @@ python manage.py migrate
</html>
```
注意,在上面的表单中,我们使用了模板指令`{% csrf_token %}`为表单添加一个隐藏域(type属性值为hidden的input标签),它的作用是在表单中生成一个随机令牌(token)来防范[跨站请求伪造](<https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0>)(通常简称为CSRF),这也是Django在提交表单时的硬性要求,除非我们专门设置了免除CSRF令牌。下图是一个关于CSRF简单生动的例子,它来自于[维基百科](<https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5>)
注意,在上面的表单中,我们使用了模板指令`{% csrf_token %}`为表单添加一个隐藏域(type属性值为hidden的input标签),它的作用是在表单中生成一个随机令牌(token)来防范[跨站请求伪造](<https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0>)(通常简称为CSRF),这也是Django在提交表单时的硬性要求,除非我们设置了免除CSRF令牌。下图是一个关于CSRF简单生动的例子,它来自于[维基百科](<https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5>)
![](./res/CSRF.png)
用户在提交注册表单时,我们还需要对用户的输入进行验证,例如我们的网站要求用户名必须由字母、数字、下划线构成且长度在4-20个字符之间,密码的长度为8-20个字符,确认密码必须跟密码保持一致。这些验证操作首先可以通过浏览器中的JavaScript代码来完成,但是即便如此,在服务器端仍然要对用户输入再次进行验证来避免将无效的数据库交给数据库,因为用户可能会禁用浏览器的JavaScript功能,也有可能绕过浏览器的输入检查将注册数据提交给服务器,所以服务器端的用户输入检查仍然是必要的。
我们可以利用Django框架封装的表单功能来对用户输入的有效性进行检查,虽然Django封装的表单还能帮助我们定制出页面上的表单元素,但这显然是一种灵活性很差的设计,这样的功能在实际开发中基本不考虑,所以表单主要的作用就在于数据验证,具体的做法如下所示。
我们可以利用Django框架封装的表单功能来对用户输入的有效性进行检查,虽然Django封装的表单还能帮助我们定制出页面上的表单元素,但这显然是一种灵活性很差的设计,这样的功能在实际开发中基本不考虑,所以表单主要的作用就在于数据验证,具体的做法如下所示。
```Python
USERNAME_PATTERN = re.compile(r'\w{4,20}')
......@@ -99,7 +101,7 @@ class RegisterForm(forms.ModelForm):
exclude = ('no', 'regdate')
```
上面,我们定义了一个与User模型绑定的表单(继承自ModelForm),我们排除了用户编号(no)和注册日期(regdate)这两个属性,并添加了一个repassword属性用来接收从用户表单传给服务器的确认密码。我们在定义User模型时已经对用户名的最大长度进行了限制,上面我们又对确认密码的最小和最大长度进行了限制,但是这些都不足以完成我们对用户输入的验证。上面以`clean_`打头的方法就是我们自定义的验证规则。很明显,`clean_username`是对用户名的检查,而`clean_password`是对密码的检查。由于数据库二维表中不应该保存密码的原文,所以对密码做了一个简单的MD5摘要处理,实际开发中这样处理还不太够,因为有被实施反向查表法(利用彩虹表反向查询)破解用户密码的风险。为字符串生成MD5摘要的代码如下所示。
上面,我们定义了一个与User模型绑定的表单(继承自ModelForm),我们排除了用户编号(no)和注册日期(regdate)这两个属性,并添加了一个repassword属性用来接收从用户表单传给服务器的确认密码。我们在定义User模型时已经对用户名的最大长度进行了限制,上面我们又对确认密码的最小和最大长度进行了限制,但是这些都不足以完成我们对用户输入的验证。上面以`clean_`打头的方法就是我们自定义的验证规则。很明显,`clean_username`是对用户名的检查,而`clean_password`是对密码的检查。由于数据库二维表中不应该保存密码的原文,所以对密码做了一个简单的MD5摘要处理,实际开发中如果只做出这样的处理还不太够,因为即便使用了摘要,仍然有利用彩虹表反向查询破解用户密码的风险,如何做得更好我们会在后续的内容中讲到。为字符串生成MD5摘要的代码如下所示。
```Python
def to_md5_hex(message):
......@@ -131,18 +133,13 @@ from django.urls import path
from vote import views
urlpatterns = [
path('', views.show_subjects),
path('captcha/', views.get_captcha),
path('teachers/', views.show_teachers),
path('prise/', views.praise_or_criticize),
path('criticize/', views.praise_or_criticize),
path('login/', views.login, name='login'),
# 此处省略上面的代码
path('register/', views.register, name='register'),
path('admin/', admin.site.urls),
# 此处省略下面的代码
]
```
> 说明:上面的代码中我们把待会要用到的登录和验证码的URL也顺便做了映射。`path`函数还可以通过name参数给URL绑定一个逆向解析的名字,也就是说,如果需要可以从后面给的名字逆向得到对应的URL。
> 说明:`path`函数可以通过name参数给URL绑定一个逆向解析的名字,也就是说,如果需要可以从后面给的名字逆向解析出对应的URL。
我们再来定制一个非常简单的登录页。
......@@ -159,7 +156,6 @@ urlpatterns = [
<hr>
<p class="hint">{{ hint }}</p>
<form action="/login/" method="post">
<input type="hidden" name="backurl" value="{{ backurl }}">
{% csrf_token %}
<div class="input">
<label for="username">用户名:</label>
......@@ -184,9 +180,9 @@ urlpatterns = [
</html>
```
上面的登录页中,我们要求用户提供验证码,验证码全称是**全自动区分计算机和人类的公开图灵测试**,它是一种用来区分系统的使用者是计算机还是人类的程序。简单的说就是程序出一个只有人类能够回答的问题,由系统使用者来解答,由于计算机理论上无法解答程序提出的问题,所以回答出问题的用户就可以被认为是人类。大多数的网站都使用了不同类型的验证码技术来防范计算机自动注册用户或模拟用户登录(暴力破解用户密码),因为验证码具有一次消费性,而没有通过图灵测试的计算机是不能够注册或登录的。
上面的登录页中,我们要求用户提供验证码,验证码全称是**全自动区分计算机和人类的公开图灵测试**,它是一种用来区分系统的使用者是计算机还是人类的程序。简单的说就是程序出一个只有人类能够回答的问题,由系统使用者来解答,由于计算机理论上无法解答程序提出的问题,所以回答出问题的用户就可以被认为是人类。大多数的网站都使用了不同类型的验证码技术来防范用程序自动注册用户或模拟用户登录(暴力破解用户密码),因为验证码具有一次消费性,而没有通过图灵测试的程序是不能够完成注册或登录的。
在Python程序中生成验证码并不算特别复杂,但需要三方库pillow的支持(PIL的分支)。我们可以借鉴现有的方法用Python稍作封装即可。下面的代码已经实现了生成验证码图片并得到图片二进制数据的功能
在Python程序中生成验证码并不算特别复杂,但需要三方库Pillow的支持(PIL的分支),因为要对验证码图片进行旋转、扭曲、拉伸以及加入干扰信息来防范那些用OCR(光学文字识别)破解验证码的程序。下面的代码封装了生成验证码图片的功能,大家可以直接用这些代码来生成图片验证码,不要“重复发明轮子”
```Python
"""
......@@ -234,15 +230,16 @@ class Captcha(object):
self._image = None
self._fonts = fonts if fonts else \
[os.path.join(os.path.dirname(__file__), 'fonts', font)
for font in ['Action.ttf', 'Silom.ttf', 'Verdana.ttf']]
for font in ['ArialRB.ttf', 'ArialNI.ttf', 'Georgia.ttf', 'Kongxin.ttf']]
self._color = color if color else random_color(0, 200, random.randint(220, 255))
self._width, self._height = width, height
@classmethod
def instance(cls, width=200, height=75):
if not hasattr(Captcha, "_instance"):
cls._instance = cls(width, height)
return cls._instance
prop_name = f'_instance_{width}_{height}'
if not hasattr(cls, prop_name):
setattr(cls, prop_name, cls(width, height))
return getattr(cls, prop_name)
def background(self):
"""绘制背景"""
......@@ -266,7 +263,7 @@ class Captcha(object):
for ps in zip(*path)))
Draw(self._image).line(points, fill=color if color else self._color, width=width)
def noise(self, number=62, level=2, color=None):
def noise(self, number=50, level=2, color=None):
"""绘制扰码"""
width, height = self._image.size
dx, dy = width / 10, height / 10
......@@ -351,7 +348,9 @@ class Captcha(object):
self.background()
self.text(captcha_text, self._fonts,
drawings=['warp', 'rotate', 'offset'])
self.curve(), self.noise(), self.smooth()
self.curve()
self.noise()
self.smooth()
image_bytes = BytesIO()
self._image.save(image_bytes, format=fmt)
return image_bytes.getvalue()
......@@ -445,4 +444,49 @@ def login(request):
return render(request, 'login.html', {'hint': hint})
```
需要指出,上面我们设定用户登录成功时直接返回首页,而且在用户登录时并没有验证用户输入的验证码是否正确,这些我们留到下一个单元再为大家讲解。
\ No newline at end of file
映射URL。
```Python
from django.contrib import admin
from django.urls import path
from vote import views
urlpatterns = [
# 此处省略上面的代码
path('login/', views.login, name='login'),
# 此处省略下面的代码
]
```
需要指出,上面我们设定用户登录成功时直接返回首页,而且在用户登录时并没有验证用户输入的验证码是否正确,这些我们留到下一个单元再为大家讲解。另外,如果要在Django自带的管理后台中进行表单验证,可以在admin.py的模型管理类中指定`form`属性为自定义的表单即可,例如:
```Python
class UserForm(forms.ModelForm):
password = forms.CharField(min_length=8, max_length=20,
widget=forms.PasswordInput, label='密码')
def clean_username(self):
username = self.cleaned_data['username']
if not USERNAME_PATTERN.fullmatch(username):
raise ValidationError('用户名由字母、数字和下划线构成且长度为4-20个字符')
return username
def clean_password(self):
password = self.cleaned_data['password']
return to_md5_hex(self.cleaned_data['password'])
class Meta:
model = User
exclude = ('no', )
class UserAdmin(admin.ModelAdmin):
list_display = ('no', 'username', 'password', 'email', 'tel')
ordering = ('no', )
form = UserForm
list_per_page = 10
admin.site.register(User, UserAdmin)
```
\ No newline at end of file
......@@ -12,13 +12,13 @@
2. 隐藏域(隐式表单域)。在提交表单的时候,可以通过在表单中设置隐藏域向服务器发送额外的数据。例如:`<input type="hidden" name="sessionid" value="123456">`
3. Cookie。Cookie是保存在浏览器临时文件中的数据,每次请求时,请求头中会携带本站点的cookie到服务器,那么只要将sessionid写入cookie,下次请求时服务器只要读取请求头中的cookie就能够获得这个sessionid,如下图所示:
3. 本地存储。现在的浏览器都支持多种本地存储方案,包括:cookie、localStorage、sessionStorage、IndexedDB等。在这些方案中,cookie是历史最为悠久也是被诟病得最多的一种方案,也是我们接下来首先为大家讲解的一种方案。简单的说,cookie是一种以键值对方式保存在浏览器临时文件中的数据,每次请求时,请求头中会携带本站点的cookie到服务器,那么只要将sessionid写入cookie,下次请求时服务器只要读取请求头中的cookie就能够获得这个sessionid,如下图所示。
![](./res/sessionid_from_cookie.png)
需要说明的是,在HTML5时代要想在浏览器中保存数据,除了使用cookie之外,还可以使用新的本地存储API,包括localStorage、sessionStorage、IndexedDB等,如下图所示。
在HTML5时代要,除了cookie,还可以使用新的本地存储API来保存数据,就是刚才提到的localStorage、sessionStorage、IndexedDB等技术,如下图所示。
![](./res/cookie_xstorage_indexeddb.png)
![](./res/cookie_xstorage_indexeddb.png)
### Django框架对session的支持
......@@ -57,7 +57,7 @@ def login(request: HttpRequest):
user = User.objects.filter(username=username, password=password).first()
if user:
# 登录成功后将用户编号和用户名保存在session中
request.session['no'] = user.no
request.session['userid'] = user.no
request.session['username'] = user.username
return redirect('/')
else:
......@@ -67,11 +67,11 @@ def login(request: HttpRequest):
return render(request, 'login.html', {'hint': hint})
```
上面的代码中,我们设定了登录成功后会在session中保存用户的编号(`no`)和用户名(`username`),页面会重定向到首页。接下来我们可以稍微对首页的代码进行调整,在页面的右上角显示出登录用户的用户名。我们将这段代码单独写成了一个名为header.html的HTML文件,首页中可以通过在`<body>`标签中添加`{% include 'header.html' %}`来包含这个页面,代码如下所示。
上面的代码中,我们设定了登录成功后会在session中保存用户的编号(`userid`)和用户名(`username`),页面会重定向到首页。接下来我们可以稍微对首页的代码进行调整,在页面的右上角显示出登录用户的用户名。我们将这段代码单独写成了一个名为header.html的HTML文件,首页中可以通过在`<body>`标签中添加`{% include 'header.html' %}`来包含这个页面,代码如下所示。
```HTML
<div class="user">
{% if request.session.no %}
{% if request.session.userid %}
<span>{{ request.session.username }}</span>
<a href="/vote/logout">注销</a>
{% else %}
......@@ -81,7 +81,7 @@ def login(request: HttpRequest):
</div>
```
如果用户没有登录,页面会显示登录和注册的超链接;而用户登录成功后,页面上会显示用户名和注销的链接,注销链接对应的视图函数如下所示。
如果用户没有登录,页面会显示登录和注册的超链接;而用户登录成功后,页面上会显示用户名和注销的链接,注销链接对应的视图函数如下所示,URL的映射与之前讲过的类似,不再赘述
```Python
def logout(request):
......
......@@ -9,7 +9,7 @@ def praise_or_criticize(request: HttpRequest):
try:
tno = int(request.GET.get('tno', '0'))
teacher = Teacher.objects.get(no=tno)
if request.path.startswith('/vote/praise'):
if request.path.startswith('/praise'):
teacher.good_count += 1
else:
teacher.bad_count += 1
......@@ -30,19 +30,14 @@ def praise_or_criticize(request: HttpRequest):
$('.comment > a').on('click', (evt) => {
evt.preventDefault()
let a = $(evt.target)
$.ajax({
url: a.attr('href'),
type: 'get',
dataType: 'json',
success: (json) => {
if (json.code == 200) {
let span = a.next()
span.text(parseInt(span.text()) + 1)
} else if (json.code == 401) {
location.href = '/vote/login/?backurl=' + location.href
} else {
alert(json.message)
}
$.getJSON(a.attr('href'), (json) => {
if (json.code == 200) {
let span = a.next()
span.text(parseInt(span.text()) + 1)
} else if (json.code == 401) {
location.href = '/login/?backurl=' + location.href
} else {
alert(json.message)
}
})
})
......
## 日志和调试
在项目开发阶段,显示足够的调试信息以辅助开发人员调试代码还是非常必要的.
项目开发阶段,显示足够的调试信息以辅助开发人员调试代码还是非常必要的;项目上线以后,将系统运行时出现的警告、错误等信息记录下来以备相关人员了解系统运行状况并维护代码也是很有必要的。要做好这两件事件,我们需要为Django项目配置日志。
### 配置日志
Django的日志配置基本可以参照官方文档再结合项目实际需求来进行,这些内容基本上可以从官方文档上复制下来,然后进行局部的调整即可,下面给出一些参考配置。
```Python
LOGGING = {
'version': 1,
# 是否禁用已经存在的日志器
'disable_existing_loggers': False,
# 日志格式化器
'formatters': {
'simple': {
'format': '%(asctime)s %(module)s.%(funcName)s: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
'verbose': {
'format': '%(asctime)s %(levelname)s [%(process)d-%(threadName)s] '
'%(module)s.%(funcName)s line %(lineno)d: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S',
}
},
# 日志过滤器
'filters': {
# 只有在Django配置文件中DEBUG值为True时才起作用
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
# 日志处理器
'handlers': {
# 输出到控制台
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'filters': ['require_debug_true'],
'formatter': 'simple',
},
# 输出到文件(每周切割一次)
'file1': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': 'access.log',
'when': 'W0',
'backupCount': 12,
'formatter': 'simple',
'level': 'INFO',
},
# 输出到文件(每天切割一次)
'file2': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': 'error.log',
'when': 'D',
'backupCount': 31,
'formatter': 'verbose',
'level': 'WARNING',
},
},
# 日志器记录器
'loggers': {
'django': {
# 需要使用的日志处理器
'handlers': ['console', 'file1', 'file2'],
# 是否向上传播日志信息
'propagate': True,
# 日志级别(不一定是最终的日志级别)
'level': 'DEBUG',
},
}
}
```
大家可能已经注意到了,上面日志配置中的formatters是**日志格式化器**,它代表了如何格式化输出日志,其中格式占位符分别表示:
1. %(name)s - 记录器的名称
2. %(levelno)s - 数字形式的日志记录级别
3. %(levelname)s - 日志记录级别的文本名称
4. %(filename)s - 执行日志记录调用的源文件的文件名称
5. %(pathname)s - 执行日志记录调用的源文件的路径名称
6. %(funcName)s - 执行日志记录调用的函数名称
7. %(module)s - 执行日志记录调用的模块名称
8. %(lineno)s - 执行日志记录调用的行号
9. %(created)s - 执行日志记录的时间
10. %(asctime)s - 日期和时间
11. %(msecs)s - 毫秒部分
12. %(thread)d - 线程ID(整数)
13. %(threadName)s - 线程名称
14. %(process)d - 进程ID (整数)
日志配置中的handlers用来指定**日志处理器**,简单的说就是指定将日志输出到控制台还是文件又或者是网络上的服务器,可用的处理器包括:
1. logging.StreamHandler(stream=None) - 可以向类似与sys.stdout或者sys.stderr的任何文件对象输出信息
2. logging.FileHandler(filename, mode='a', encoding=None, delay=False) - 将日志消息写入文件
3. logging.handlers.DatagramHandler(host, port) - 使用UDP协议,将日志信息发送到指定主机和端口的网络主机上
4. logging.handlers.HTTPHandler(host, url) - 使用HTTP的GET或POST方法将日志消息上传到一台HTTP 服务器
5. logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False) - 将日志消息写入文件,如果文件的大小超出maxBytes指定的值,那么将重新生成一个文件来记录日志
6. logging.handlers.SocketHandler(host, port) - 使用TCP协议,将日志信息发送到指定主机和端口的网络主机上
7. logging.handlers.SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None, timeout=1.0) - 将日志输出到指定的邮件地址
8. logging.MemoryHandler(capacity, flushLevel=ERROR, target=None, flushOnClose=True) - 将日志输出到内存指定的缓冲区中
上面每个日志处理器都指定了一个名为“level”的属性,它代表了日志的级别,不同的日志级别反映出日志中记录信息的严重性。Python中定义了六个级别的日志,按照从低到高的顺序依次是:NOTSET、DEBUG、INFO、WARNING、ERROR、CRITICAL。
最后配置的**日志记录器**是用来真正输出日志的,Django框架提供了如下所示的内置记录器:
1. django - 在Django层次结构中的所有消息记录器
2. django.request - 与请求处理相关的日志消息。5xx响应被视为错误消息;4xx响应被视为为警告消息
3. django.server - 与通过runserver调用的服务器所接收的请求相关的日志消息。5xx响应被视为错误消息;4xx响应被记录为警告消息;其他一切都被记录为INFO
4. django.template - 与模板渲染相关的日志消息
5. django.db.backends - 有与数据库交互产生的日志消息,如果希望显示ORM框架执行的SQL语句,就可以使用该日志记录器。
日志记录器中配置的日志级别有可能不是最终的日志级别,因为还要参考日志处理器中配置的日志级别,取二者中级别较高者作为最终的日志级别。
### 配置Django-Debug-Toolbar
Django-Debug-Toolbar是辅助Django项目开发的神器,只要配置了它,就可以很方便的查看到以下内容,这些信息对了解项目的运行状况以及优化Web应用性能都是至关重要的。
| 项目 | 说明 |
| ----------- | --------------------------------- |
| Versions | Django的版本 |
| Time | 显示视图耗费的时间 |
| Settings | 配置文件中设置的值 |
| Headers | HTTP请求头和响应头的信息 |
| Request | 和请求相关的各种变量及其信息 |
| StaticFiles | 静态文件加载情况 |
| Templates | 模板的相关信息 |
| Cache | 缓存的使用情况 |
| Signals | Django内置的信号信息 |
| Logging | 被记录的日志信息 |
| SQL | 向数据库发送的SQL语句及其执行时间 |
1. 安装Django-Debug-Toolbar。
```Shell
pip install django-debug-toolbar
```
2. 配置 - 修改settings.py。
```Python
INSTALLED_APPS = [
'debug_toolbar',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
]
DEBUG_TOOLBAR_CONFIG = {
# 引入jQuery库
'JQUERY_URL': 'https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js',
# 工具栏是否折叠
'SHOW_COLLAPSED': True,
# 是否显示工具栏
'SHOW_TOOLBAR_CALLBACK': lambda x: True,
}
```
3. 配置 - 修改urls.py。
```Python
if settings.DEBUG:
import debug_toolbar
urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls)))
```
4. 使用 - 在页面右侧可以看到一个调试工具栏,上面包括了如前所述的调试信息,包括:执行时间、项目设置、请求头、SQL、静态资源、模板、缓存、信号等,查看起来非常的方便。
\ No newline at end of file
......@@ -182,7 +182,7 @@ ipython最直观的优点:
resp = requests.get('http://api.tianapi.com/allnews/?key=请使用自己申请的Key&col=7&num=50')
```
> 说明:上面使用了天行数据提供的数据接口,需要的话可以自行去[天行数据](<https://www.tianapi.com/>)的网站注册开通。
> 说明:上面使用了天行数据提供的数据接口,需要的话可以自行去[天行数据](<https://www.tianapi.com/>)的网站注册开通,调用接口的时候要填写注册成功后系统分配给你的key
3. 使用反序列化将JSON字符串解析为字典并获取新闻列表。
......@@ -225,5 +225,5 @@ ipython最直观的优点:
)
```
> 说明:上面的代码使用了[螺丝帽](<https://luosimao.com/>)的短信网关,利用短信网关发送短信是需要支付费用的,但是一般的平台都会提供免费测试的短信,但是发送短信必须遵守平台的规则,违规的短信是无法发送的。上面发短信时使用的短信模板(“发现一条您可能感兴趣的新闻 - ###,详情点击https://news.china.com/### 查看。”)和短信签名(“【Python小课】”)需要登录螺丝帽管理平台进行配置,如果不清楚如何配置,这些平台都是有客服的哟
> 说明:上面的代码使用了[螺丝帽](<https://luosimao.com/>)提供的短信网关服务,利用短信网关发送短信是需要支付费用的,但是一般的平台都会提供若干条免费的测试短信。发送短信必须遵守平台的规则,违规的短信是无法发送的。上面发短信时使用的短信模板(“发现一条您可能感兴趣的新闻 - ###,详情点击https://news.china.com/### 查看。”)和短信签名(“【Python小课】”)需要登录螺丝帽管理平台进行配置,如果不清楚如何配置,可以联系平台的客服人员进行咨询
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册