0%

  • export_urls.csv是阿里云oss导出的url表,其中有四个列表字段,依次是:id,barcode,type,serial,img_url

  • 2.xlsx 是所依据的excel表格,固定的第一列是barcode。

  • data.xlsx是生成的结果数据。

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
# coding: utf-8
import re
import pandas as pd
from openpyxl import Workbook

rz = re.compile(r'/(\d+-\d)-.+jpg')

d = {}

dkey = {}


def open_csv():
for file in file_paths:
ex = pd.read_csv(file)
exs = ex.values.tolist()
for i in exs:
url = i[4]
url_id = rz.findall(url)
print(url_id)
if len(url_id)== 0 :
continue
url_id = url_id[0]
if url_id not in d:
d.update({url_id: [url]})
else:
d[url_id].append(url)

for k, v in d.items():
ks = str(k).split('-')
k1 = ks[0]
k2 = ks[1]
if k1 not in dkey:
if str(k2) == '1':
dkey.update({k1: {'0': [], '1': v}})
else:
dkey.update({k1: {'0': v, '1': []}})
else:
if str(k2) == '1':
dkey[k1]['1'].extend(v)
else:
dkey[k1]['0'].extend(v)

for k, v in dkey.items():
print(type(k), v)
wb.append([str(k), str(v['0']), str(v['1'])])

for i in orl_key:
if str(i) not in dkey:
print(type(i), 'iii')
wb.append([str(i)])


if __name__ == "__main__":
orl_urlids = pd.read_excel(r'2.xlsx')
orl_urls = orl_urlids.values.tolist()
orl_key = [i[0] for i in orl_urls]

wk = Workbook()
wb = wk.active

file_paths = ['./export_urls.csv']
open_csv()
wk.save(r'data.xlsx')
# """

gorm.Model源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package gorm

import "time"

// Model base model definition, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embedded in your models
// type User struct {
// gorm.Model
// }
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time `sql:"index"`
}

所以我们创建结构体的时候的就不需要包含这几个字段了,不然后会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import (
"time"
)

type User struct {
Id int `json:"id" form:"id" gorm:"primary_key"` // 主键ID
CreatedAt time.Time `gorm:""json:"createdAt"` // 创建时间
UpdatedAt time.Time `gorm:""json:"updatedAt"` // 更新时间
DeletedAt *time.Time `gorm:"index"json:"deletedAt"` // 删除时间
Name string `gorm:"not null;"json:"name"` // 姓名
...
}

func (*User) TableName() string {
return "user"
}

func (m *User) IsAdministrator() bool {
if m == nil || m.Id <= 0 {
return false
}
return m.Role == 0 || m.Role == 1
}

报错

1
2
3
4
5
6
7
8
9
10
11
12
13
panic: Error 1146: Table 'XXXX.user' doesn't exist

goroutine 1 [running]:
github.com/jinzhu/gorm.mysql.HasIndex(0x1a3ebc0, 0xc0000fe240, 0x203000, 0x19037e8, 0x4, 0xc00059ddc0, 0x13, 0x30c8300)
/Users/samtake/go/pkg/mod/github.com/jinzhu/gorm@v1.9.12/dialect_mysql.go:189 +0x31f
github.com/jinzhu/gorm.(*Scope).addIndex(0xc0004ec380, 0x18ecd00, 0xc00059ddc0, 0x13, 0xc00037b5a0, 0x2, 0x2)
/Users/samtake/go/pkg/mod/github.com/jinzhu/gorm@v1.9.12/scope.go:1212 +0x8d
github.com/jinzhu/gorm.(*DB).AddIndex(0xc00001dee0, 0xc00059ddc0, 0x13, 0xc00037b5a0, 0x2, 0x2, 0x1)
/Users/samtake/go/pkg/mod/github.com/jinzhu/gorm@v1.9.12/main.go:706 +0xac
github.com/jinzhu/gorm.(*Scope).autoIndex(0xc000559900, 0xc000559900)
/Users/samtake/go/pkg/mod/github.com/jinzhu/gorm@v1.9.12/scope.go:1312 +0x9a0
github.com/jinzhu/gorm.(*Scope).createTable(0xc000559900, 0x19037e8)
/Users/samtake/go/pkg/mod/github.com/jinzhu/gorm@v1.9.12/scope.go:1194 +0x792

改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import (
"time"

"github.com/jinzhu/gorm"
)

type User struct {
gorm.Model
Name string `gorm:"not null;"json:"name"` // 姓名
...
}

func (*User) TableName() string {
return "user"
}

func (m *User) IsAdministrator() bool {
if m == nil || m.ID <= 0 {
return false
}
return m.Role == 0 || m.Role == 1
}

Mac首选brew安装:

1
2
brew tap go-swagger/go-swagger
brew install go-swagger

使用

1
2
swagger generate spec -o ./swagger.json --scan-models
swagger serve -F=swagger swagger.json

其中 swagger.json文件是使用过命令行来生成的,然后进去编写自己的规则。

小编直接拉去别的项目swagger.json文件时,跑起来出错了,你只需要通过swagger命令行创建后再复制内容进去即可。
No operations defined in spec!

swagger01.png

资料:

如何使用 SwaggerUI 创建 Golang API 文档?

go-swagger安装及使用

目录

表设计

  • DDL(Data Definition Language)数据库模式定义语言
  • 表字段类型选择。
  • 3范式,三种表间关系:一对一,一对多,多对多。

表使用

  • 基本查询语句。
  • SQL语句优先级。
  • 链接查询:子查询,组合查询。
  • select…from…where…group by…having…order by..limit

DDL

库的创建
create database 库名;
create database if not existe 库名;

更改库的字符集
alter database books character set gbk;

库的删除
drop database if exists 库名;

表的创建

1
2
3
4
5
6
7
8
9
10
11
12
create table 表名(
列名 列的类型【(长度)约束】
列名 列的类型【(长度)约束】
.......
列名 列的类型【(长度)约束】)

create table book(
id int,
bname varchar(20),
prince double,
authorid int,
publishbate datetime)

表的修改
alter table 表名 add/drop/modify/change column 列名 列类型 约束;

  • 修改列名 alter table 表名 change column 旧列名 新列名 类型;
  • 修改列的类型及约束 alter table 表名 modify column 列名 要修改的类型
  • 添加新列 alter table author add column annual double;
  • 删除列 alter table author drop column annual ;
  • 修改表名 alter table author rename to bookauthor;
  • 表的删除 drop table if exists 表名;
  • 查看 show tables
  • 通用的写法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    drop database if exists 旧库名;

    create batabase 新库名;

    drop table if exists 旧表名;

    create table 表名();

    desc 表名 (查看表结构)
  • 表的复制

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #1.仅仅复制表的结构
    create table 新表名 like author;
    #2.复制表的结构+数据
    create table 新表名
    select *from 旧表名;
    #3.只复制部分数据
    create teble 新表名
    select 列名,..
    from 旧表名
    where 筛选条件;
    #4.仅仅复制某些结构
    create table 新表名
    select 列名,..
    from 旧表名
    where 0(谁都不满足的条件);

表字段类型

数值型

场景 类型 字节 举例 描述
- tinyint 1 - -
- smallint 2 - -
- mediumint 3 - -
- int
integer
4
4
- -
- bigint 1 8 -
  • 如何设置有符号和无符号
    默认是有符号,设置无符号追加unsigned

  • 插入数值超出整型范围
    报异常:out of range,并且插入的是临界值

  • 如果不设置长度会有默认的长度
    zerofill(零填充,默认无符号),显示结果的最大宽度,不过会在左边用0填充

小数

场景 类型 举例 描述
- dec
decimal
dec(M,D)
decimal(M,D)
定点型
- float
double
float(M,D)
double(M,D)
浮点型
  • M是整数部位加小数部位的总长度,D是小数点后保留的位数
    超过插入的是临界值

  • M和D都可省略,如果是decimal,M默认为10,D默认为0
    如果是float和double,则会根据插入的数值决定

  • 定点型精确度较高,要求插入数值精度较高优先用,如货币运算等则等
    其他一般用float就可以。

  • 选择类型越简单越好,保存数值越小越好

字符型

场景 类型 举例 描述
较短的文本 char
varchar
char(M)
varchar(M)
M表示最大的字符数,可省略,默认为1 固定长度的字符 比较耗费空间
M表示最大的字符数,不可省略 可变长度的字符 比较节省空间
较长的文本 text
blob
- 较长的二进制数据

日期

场景 类型 举例 描述
- date - -
- datetime - datetime范围1000-1-1—-9999-12-31,不受时区影响
- timestamp - 受时区影响
- time - -
- year - -

常见约束

场景 字段 举例 描述
- not null - 非空,用于保证该字段的值不能为空,如姓名、学号
- default - 默认,用于保证该字段有默认值,如性别
- primary key - 主键,用于保证该字段的值具有唯一性,并且非空,如学号、员工编号
- unique - 唯一、用于保证该字段的值具有唯一性,可以为空,如座位号
- check - 检查约束,mysql中不支持,如年龄、性别
- foreign key - 外键,用于限制两个表的关系,用于保证该字段的值必须来自主表的关联列的值。在从表添加外键约束,用于引用主表中某列的值。
  • 添加约束的时机:创建表时/修改表时

  • 约束的添加分类:

    • 列级约束:六大约束语法都支持但外键约束没有效果
    • 表级约束;除了非空、默认,其他的都支持

创建表时添加约束

添加列级约束

直接在字段名和类型后面追加 约束类型即可
只支持:默认、非空、主键、唯一

1
2
3
4
5
6
7
8
9
10
11
12
create table 表名(
字段名 字段类型 列级约束,
字段名 字段类型,
表级约束

create table stuinfo(
id int primary key,
stuname varchar(20) not null,
gender char(1) check(gender='男' or gender = '女'),
age int default 18
majorid int foreign key references major(id)
);

添加表级约束

1
2
3
4
5
6
7
8
9
10
11
12
13

create table stuinfo(
id int ,
stuname varchar(20) ,
gender char(1) ,
age int,
majorid int,

constraint pk primary key(id),#主键
constraint uq unique(seat),#唯一键
constraint ck check(gender='男' or gender = '女'),
constraint fk_syuinfo_major foreign key(majorid) references major(id)#外键
);

在各个字段的最下面添加:<constraint 约束名> 约束类型(字段名)

主键与唯一的对比

  • 主键:保持唯一性 / 不允许为空/一个表中只至少有一个/两个列可以组合为一个主键但不推荐
  • 唯一:保持唯一性 / 允许为空 /可以有多个/可以组合但不推荐

外键

  • 要求在从表设置外键关系

  • 从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求

  • 主表的关联列必须是一个key(一般是主键或唯一)

  • 插入数据时,先插入主表数据再插入从表

  • 删除数据先删除从表再删除主表

修改表时添加约束

列级约束:alter table 表名 modify column 字段名 字段类型 新约束;

表级约束:alter table 表名 add <constriaint 约束名> 约束类型(字段名)<外键的引用>;

  • 添加非空约束 alter table 表名 modify column 列名 要修改的类型 not null

  • 默认约束 alter table 表名 modify column 列名 int default 18

  • 添加主键
    列级约束 alter table 表名 modify column 列名 int default key;
    表级约束 alter table 表名 add primary key(列名)

  • 添加唯一
    列级约束 alter table 表名 add primary key(列名) 要修改的类型 notnull
    表级约束 alter table 表名 add unique(列名)

  • 添加外键 alter table 表名 add foreign key(majorid) references major(id)

修改表时删除约束

删除非空 alter table 表名 modify column 列名 varchar(20) null;
删除默认约束 alter table 表名 modify column 列名 int;
删除主键 alter table 表名 drop primary key;
删除唯一 alter table 表名 drop index 列名;
删除外键 alter table 表名 drop foreign key 列名;

3范式

第一范式(1NF)

保证每列的原子性。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库满足了第一范式。

例如将地址的拆分:

编号 姓名 地址
1 张三 广东广州天河
2 李四 广东佛山禅城
3 王五 广东广州科学城
编号 姓名 省份 城市 地址
1 张三 广东 广州 天河
2 李四 广东 佛山 禅城
3 王五 广东 广州 科学城

第二范式(2NF)

保证一张表只描述一件事情。
在满足第一范式的基础上,数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖,也即所有非关键字段都完全依赖于任一组候选关键字。

举例:
| 学号 | 姓名 | 年龄 | 课程 | 成绩 | 学分 |
| :—–| :—–| :—-| :—-| :—-| :—-|
| 1 | 张三 | 20 | 数学 | 90 | 1 |
| 2 | 李四 | 20 | 语文 | 90 | 1 |
| 3 | 王五 | 20 | 英语 | 50 | 1 |

上表满足第一范式,即每个字段不可再分,但这张表的设计并不满足第二范式。因为这张表里面描述了两件事情:学生信息、课程信息,”学分”完全依赖于”课程名称”、”姓名”与”年龄”完全依赖于”学号”。这么做的后果是:

  • 数据冗余:同一门课程由n个学生选修,”学分”重复n-1次;同一个学生选修了m门课程,姓名和年龄重复m-1次

  • 更新异常:若调整了某门课程的学分,数据表中所有行的”学分”值都需要更新,否则会出现同一门课程学分不同的情况

  • 插入异常:假设要开一门新课程,暂时没有人选修,那么由于没有”学号”关键字,”课程”与”学分”也无法记录入数据库

  • 删除异常:假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,”课程”和”学分”也被删除了,显然,这最终可能会导致插入异常

优化后的表设计如下:
| 学号 | 姓名 | 年龄 |
| :—–| :—–| :—-|
| 1 | 张三 | 20 |
| 2 | 李四 | 20 |
| 3 | 王五 | 20 |

课程 学分
数学 1
语文 1
英语 1
学号 课程 成绩
1 数学 90
2 语文 90
3 英语 50

增加了表,将学生信息与课程信息通过一张中间表关联,很好地解决了上面的几个问题,这就是第二范式的中心—-保证一张表只讲一件事情。

第三范式(3NF)

数据库表中如果不存在非关键字段任一候选关键字段的传递函数依赖则符合第三范式,所谓传递函数依赖指的是如果存在”A–>B–>C”的决定关系,则C传递函数依赖于A。也就是说中的字段和主键直接对应不依靠其他中间字段,说白了就是,决定某字段值的必须是主键。

举例:

学号 姓名 年龄 学院地点 学院电话
1 张三 20 计算机学院 9号楼
2 李四 20 计算机学院 9号楼
3 王五 20 计算机学院 9号楼

从这张数据库表结构中可以看出:

  • “姓名”、”年龄”、”学院”和主键”学号”直接关联。

  • 但是”学院地点”、”学院电话”却不直接和主键”学号”相关联,和”学院电话”直接相关联的是”学院”。

  • 如果表结构这么设计,同样会造成和第二范式一样的数据冗余、更新异常、插入异常、删除异常的问题。

优化后的表设计:

学院 学院地点 学院电话
计算机学院 9号楼 11111
艺术学院 8号楼 11112
机电学院 7号楼 11113
学号 姓名 年龄 学院
1 张三 20 计算机学院
2 李四 20 计算机学院
3 王五 20 计算机学院

文章参考:
MySQL数据库三范式

草根学Python

菜鸟教程Python

基本数据类型

数字

Number:数字
int:整数
float:浮点数

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
#!/usr/bin/python3

counter = 100 # 整型变量
miles = 1000.0 # 浮点型变量
name = "r00unoob" # 字符串



print (counter)
print (miles)
print (name)

print (5/2) #除

print (5//2) #整除


print (0b10) #二进制
print (0o10) #八进制
print (0x10) #十六进制


print (bin(123)) #bin转二进制
print (int(0o10)) #int转十进制
print (hex(0o10)) #转十六进制
print (oct(123)) #转十六进制

布尔

bool:布尔类型

1
2
3
4
5
6
7
8
#!/usr/bin/python3

print (bool(True))
print (bool(False))
print (bool(None))
print (bool(""))
print (bool({}))
print (bool([1,2,3]))

复数

complex:复数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
```


## 字符串
单引号、双引号、三个单引号、三个双引号、

```bash
#!/usr/bin/python3

print ('hello')
print ("i'm hello")
print ('i\'m hello')
print ('''i'm
hello
mm
nn
''')

转移字符

1
2
3
4
\n  #换行
\r #回车
\' #单引号
\t #横向制表符

字符串运算

1
2
3
4
5
6
7
print ('hello'+'hello') #两个字符串的拼接
print ('hello'[0])
print ('hello'[-1])
print ('hello'[0:3])
print ('hello'[0:-3])
print ('hello'[0:30])
print ('hello'[3:])
1
2
3
4
5
6
7
hellohellohello
h
o
hel
he
hello
lo

list

1
2
3
4
5
#!/usr/bin/python3

print ([1,2,3,"hhh",False])

print ([[1,2,3,"hhh",False],[7,9],9])
1
2
[1, 2, 3, 'hhh', False]
[[1, 2, 3, 'hhh', False], [7, 9], 9]

列表的基本操作

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

print ([[1,2,3,"hhh",False],[7,9],9]) #列表的组成可以是嵌套列表

myList = [1,2,3,"hhh",False]
print (myList[3]) #得到的是一个元素
print (myList[3:]) #得到的是一个列表


myList2 = ['添加的元素']
print(myList+myList2)
1
2
3
4
[[1, 2, 3, 'hhh', False], [7, 9], 9]
hhh
['hhh', False]
[1, 2, 3, 'hhh', False, '添加的元素']

tuple

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

tup1 = ('Google', 'Runoob', 1997, 2000)
print(tup1)
tup2 = (1, 2, 3, 4, 5 )
print(tup2)
tup3 = "a", "b", "c", "d" # 不需要括号也可以
print(tup3)

tup4 = ()
print(tup4)
1
2
3
4
('Google', 'Runoob', 1997, 2000)
(1, 2, 3, 4, 5)
('a', 'b', 'c', 'd')
()
1
2
3
4
5
6
#!/usr/bin/python3

#元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用

tup1 = (50,)
print(tup1)

访问元组

1
2
3
4
5
tup1 = ('Google', 'Runoob', 1997, 2000)
tup2 = (1, 2, 3, 4, 5, 6, 7 )

print ("tup1[0]: ", tup1[0])
print ("tup2[1:5]: ", tup2[1:5])
1
2
tup1[0]:  Google
tup2[1:5]: (2, 3, 4, 5)

修改元组

元组中的元素值是不允许修改的,但我们可以对元组进行连接组合

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')

# 以下修改元组元素操作是非法的。
# tup1[0] = 100

# 创建一个新的元组
tup3 = tup1 + tup2
print (tup3)
1
(12, 34.56, 'abc', 'xyz')

删除元组

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

tup = ('Google', 'Runoob', 1997, 2000)

print (tup)
del tup
print ("删除后的元组 tup : ")

#print (tup)

print ('hello')

删除之后在使用,会存在报错:

1
2
3
4
5
6
('Google', 'Runoob', 1997, 2000)
删除后的元组 tup :
Traceback (most recent call last):
File "main.py", line 9, in
print (tup)
NameError: name 'tup' is not defined

元组内置函数

方法 描述
len(tuple) 计算元组元素个数
max(tuple) 返回元组中元素最大值
min(tuple) 返回元组中元素最小值
tuple(iterable) 将可迭代系列转换为元组
1
2
3
4
5
#!/usr/bin/python3

list1= ['Google', 'Taobao', 'Runoob', 'Baidu']
tuple1=tuple(list1)
print(tuple1)
1
('Google', 'Taobao', 'Runoob', 'Baidu')

字典

d = {key1 : value1, key2 : value2 }

1
2
3
dict = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
dict1 = { 'abc': 456 }
dict2 = { 'abc': 123, 98.6: 37 }

访问字典

1
2
3
4
5
6
#!/usr/bin/python3

dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

print ("dict['Name']: ", dict['Name'])
print ("dict['Age']: ", dict['Age'])
1
2
dict['Name']:  Runoob
dict['Age']: 7

修改字典

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/python3

dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

dict['Age'] = 8 # 更新 Age
dict['School'] = "菜鸟教程" # 添加信息


print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])
1
2
dict['Age']:  8
dict['School']: 菜鸟教程

删除字典元素

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/python3

dict = {'School': '社会','Name': 'Runoob', 'Age': 7, 'Class': 'First'}

#del dict['Name'] # 删除键 'Name'
#dict.clear() # 清空字典
#del dict # 删除字典

print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])
1
2
dict['Age']:  7
dict['School']: 社会

键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行

1
2
3
4
5
#!/usr/bin/python3

dict = {['Name']: 'Runoob', 'Age': 7}

print ("dict['Name']: ", dict['Name'])
1
2
3
4
11111Traceback (most recent call last):
File "main.py", line 3, in
dict = {['Name']: 'Runoob', 'Age': 7}
TypeError: unhashable type: 'list'

内置函数
| 方法 | 描述 |
| :—–:| :—-: |
| len(dict) | 计算字典元素个数,即键的总数 |
| str(dict) | 输出字典,以可打印的字符串表示 |
|type(variable)|返回输入的变量类型,如果变量是字典就返回字典类型|

内置方法
| 方法 | 描述 |
| :—–| :—-|
|radiansdict.clear()|删除字典内所有元素|
|radiansdict.copy()|返回一个字典的浅复制|
|radiansdict.fromkeys()|创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值|
|radiansdict.get(key, default=None)|返回指定键的值,如果值不在字典中返回default值|
|key in dict|如果键在字典dict里返回true,否则返回false|
|radiansdict.items()|以列表返回可遍历的(键, 值) 元组数组|
|radiansdict.keys()|返回一个迭代器,可以使用 list() 来转换为列表|
|radiansdict.setdefault(key, default=None)|和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default|
|radiansdict.update(dict2)|把字典dict2的键/值对更新到dict里|
|radiansdict.values()|返回一个迭代器,可以使用 list() 来转换为列表|
|pop(key[,default])|删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。|
|popitem()|随机返回并删除字典中的最后一对键和值|

集合

集合(set)是一个无序的不重复元素序列。

可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

1
2
3
parame = {value01,value02,...}
#或者
set(value)

集合具有去重功能

1
2
3
4
#!/usr/bin/python3

basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket)
1
{'pear', 'apple', 'banana', 'orange'}

快速判断元素是否在集合内

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

a = {x for x in 'abracadabra' if x not in 'abc'}
a = set('abracadabra')
b = set('alacazam')

print("a:",a)
print("集合a中包含而集合b中不包含的元素:",a - b)
print("集合a或b中包含的所有元素:",a | b )
print("集合a和b中都包含了的元素:",a & b)
print("不同时包含于a和b的元素:",a ^ b)
1
2
3
4
5
a: {'r', 'a', 'b', 'c', 'd'}
集合a中包含而集合b中不包含的元素: {'b', 'r', 'd'}
集合a或b中包含的所有元素: {'z', 'r', 'a', 'l', 'b', 'm', 'c', 'd'}
集合a和b中都包含了的元素: {'c', 'a'}
不同时包含于a和b的元素: {'z', 'r', 'l', 'b', 'm', 'd'}

类似列表推导式,同样集合支持集合推导式(Set comprehension)

1
2
3
4
#!/usr/bin/python3

a = {x for x in 'abracadabra' if x not in 'abc'}
print("a:",a)
1
a: {'r', 'd'}

集合的基本操作

添加元素

1
2
3
4
5
6
7
8
9
#!/usr/bin/python3

thisset = set(("Google", "Runoob", "Taobao"))
thisset.add("Facebook")
print(thisset)
thisset.update({1,3})
print(thisset)
thisset.update([1,4],[5,6])
print(thisset)
1
2
3
{'Google', 'Runoob', 'Taobao', 'Facebook'}
{1, 'Taobao', 3, 'Runoob', 'Facebook', 'Google'}
{1, 'Taobao', 3, 4, 5, 6, 'Runoob', 'Facebook', 'Google'}

移除元素

1
2
3
4
5
6
thisset.remove("Taobao") # 不存在会发生错误

thisset.discard("Taobao") #不存在不会发生错误

// pop 方法会对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除
thisset.pop() #随机删除集合中的一个元素

计算集合元素个数

1
len(thisset)

清空集合

1
thisset.clear()

判断元素是否在集合中存在

1
"Runoob" in thisset

集合内置方法完整列表
| 方法 | 描述|
| :—–| :—-|
| add() | 为集合添加元素
| clear() | 移除集合中的所有元素
| copy() | 拷贝一个集合
| difference() | 返回多个集合的差集
| difference_update() | 移除集合中的元素,该元素在指定的集合也存在。
| discard() | 删除集合中指定的元素
| intersection() | 返回集合的交集
| intersection_update() | 返回集合的交集。
| isdisjoint() | 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。
issubset() | 判断指定集合是否为该方法参数集合的子集。
issuperset() | 判断该方法的参数集合是否为指定集合的子集
pop() | 随机移除元素
remove() | 移除指定元素
symmetric_difference() | 返回两个集合中不重复的元素集合。
| symmetric_difference_update() | 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。
| union() | 返回两个集合的并集
| update() | 给集合添加元素

end 关键字

关键字end可以用于将结果输出到同一行,或者在输出的末尾添加不同的字符

1
2
3
4
5
6
7
8
#!/usr/bin/python3

# Fibonacci series: 斐波纳契数列
# 两个元素的总和确定了下一个数
a, b = 0, 1
while b < 1000:
print(b, end=',')
a, b = b, a+b
1
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

条件控制

1
2
3
4
5
6
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3

if 嵌套:可以把 if…elif…else 结构放在另外一个 if…elif…else 结构中

1
2
3
4
5
6
7
8
9
10
11
12
if 表达式1:
语句
if 表达式2:
语句
elif 表达式3:
语句
else:
语句
elif 表达式4:
语句
else:
语句

循环语句

while

1
2
while 判断条件(condition):
执行语句(statements)……

while 循环使用 else 语句

1
2
3
4
while <expr>:
<statement(s)>
else:
<additional_statement(s)>

for中使用了 break 语句,break 语句用于跳出当前循环体:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

sites = ["Baidu", "Google","Runoob","Taobao"]
for site in sites:
if site == "Runoob":
print("菜鸟教程!")
break
print("循环数据 " + site)
else:
print("没有循环数据!")
print("完成循环!")
1
2
3
4
循环数据 Baidu
循环数据 Google
菜鸟教程!
完成循环!

range()函数

1
2
3
4
#!/usr/bin/python3

for i in range(5):
print(i)
1
2
3
4
5
0
1
2
3
4

使用range指定区间的值

1
2
for i in range(5,9) :
print(i)
1
2
3
4
5
6
7
8

使range以指定数字开始并指定不同的增量(甚至可以是负数,有时这也叫做’步长’):

1
2
3
4
5
6
7
for i in range(0, 10, 3) :
print(i)

print("负数")

for i in range(-10, -100, -30) :
print(i)
1
2
3
4
5
6
7
8
0
3
6
9
负数
-10
-40
-70

结合range()和len()函数以遍历一个序列的索引

1
2
3
4
5
#!/usr/bin/python3

a = ['Google', 'Baidu', 'Runoob', 'Taobao', 'QQ']
for i in range(len(a)):
print(i, a[i])
1
2
3
4
5
0 Google
1 Baidu
2 Runoob
3 Taobao
4 QQ

使用range()函数来创建一个列表

1
2
3
4
#!/usr/bin/python3

myList=list(range(5))
print(myList)
1
[0, 1, 2, 3, 4]

break 和 continue 语句及循环中的 else 子句

break 语句可以跳出 forwhile 的循环体。如果你从 forwhile 循环中终止,任何对应的循环 else 块将不执行。

continue 语句被用来告诉 Python 跳过当前循环块中的剩余语句,然后继续进行下一轮循环

while 中使用 break:

1
2
3
4
5
6
7
8
9
#!/usr/bin/python3

n = 5
while n > 0:
n -= 1
if n == 2:
break
print(n)
print('循环结束。')
1
2
3
4
3
循环结束。

while 中使用 continue:

1
2
3
4
5
6
7
8
9
#!/usr/bin/python3

n = 5
while n > 0:
n -= 1
if n == 2:
continue
print(n)
print('循环结束。')
1
2
3
4
5
4
3
1
0
循环结束。

pass 语句

pass 不做任何事情,一般用做占位语句

1
2
3
4
5
#!/usr/bin/python3

while True:
print("....")
pass # 等待键盘中断 (Ctrl+C)

迭代器

  • 迭代器是一个可以记住遍历的位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  • 迭代器有两个基本的方法:iter() 和 next()。

字符串,列表或元组对象都可用于创建迭代器:

1
2
3
4
5
6
#!/usr/bin/python3

list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
print (next(it)) # 输出迭代器的下一个元素
print (next(it))
1
2
1
2

使用for语句遍历迭代器

1
2
3
4
5
6
#!/usr/bin/python3

list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
for x in it:
print (x, end=" ")
1
1 2 3 4

使用next()遍历迭代器

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/python3

import sys # 引入 sys 模块

list=[1,2,3,4]
it = iter(list) # 创建迭代器对象

while True:
try:
print (next(it))
except StopIteration:
sys.exit()
1
2
3
4
1
2
3
4

创建一个迭代器

  • 把一个类作为一个迭代器使用需要在类中实现两个方法 iter() 与 next() 。

  • Python 的构造函数为 init(), 它会在对象初始化的时候执行。

  • __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。

  • __next__() 方法会返回下一个迭代器对象。

创建一个返回数字的迭代器,初始值为 1,逐步递增 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
x = self.a
self.a += 1
return x

myclass = MyNumbers()
myiter = iter(myclass)

print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
1
2
3
4
5
1
2
3
4
5

StopIteration

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration

myclass = MyNumbers()
myiter = iter(myclass)

for x in myiter:
print(x)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

生成器

  • 在 Python 中,使用了 yield 的函数被称为生成器(generator)。

  • 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

  • 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

  • 调用一个生成器函数,返回的是一个迭代器对象。

使用 yield 实现斐波那契数列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python3

import sys

def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成

while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()

函数

1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash
1
2
3
```

```bash

概念名词

SAAS

SAAS是Software-as-a-Service(软件即服务)的简称.

  • 厂商将应用软件统一部署在自己的服务器上,客户可以根据自己实际需求,通过互联网向厂商定购所需的应用软件服务,按定购的服务多少和时间长短向厂商支付费用,并通过互联网获得厂商提供的服务.
  • 用户不用再购买软件,而改用向提供商租用基于Web的软件,来管理企业经营活动,且无需对软件进行维护,服务提供商会全权管理和维护软件,软件厂商在向客户提供互联网应用的同时,也提供软件的离线操作和本地数据存储,让用户随时随地都可以使用其定购的软件和服务.

ERP

ERP系统是企业资源计划的简称.

  • ERP系统主要功能:有产品采集、产品管理、分类管理、订单管理、物流管理、报表管理.
  • 软件举例:进销存软件、

CRM

CRM即客户关系管理.

  • 通常所指的CRM,指用计算机自动化分析销售、市场营销、客户服务以及应用等流程的软件系统.

BI

BI(Business Intelligence),商业智能,又称商业智能或商务智能.

  • 指用数据仓库技术、在线分析处理技术、数据挖掘和数据展现技术进行数据分析以实现商业价值。
  • 商业智能通常可以将企业中现有的数据转化为知识,帮助企业做出明智的业务经营决策的工具。

SAP

它一般指的是一家生产设计Erp系统的公司简称。

  • SAP公司是全球最大的企业管理和协同化商务解决方案供应商、世界第三大的独立软件供应商、全球第二大云公司。

BPO

BPO(Business Process Outsourcing)商业流程委外,又称业务流程外包或经营外包.

  • 是指把特定的商业工序外派给第三方服务供应商.

SOA

SOA(Service-Oriented Architecture),面向服务的体系结构。

  • SOA是一种根据业务流程(Business Process)来组织功能,并将功能封装成为可互操作的服务的软件架构。

大数据、数据分析

数据分析01.jpeg

一文读懂大数据平台——写给大数据开发初学者的话!

这里推荐极客时间出品的《数据分析实战45讲》
基础+算法+实战+数据可视化

中台

阿里中台架构

双中台
说透中台01.jpeg

这里推荐王健的《说透中台》

总结

各自的技术栈都不一样,做之前先调研:

  1. 数据:数据分析用 python,但自己之前接触的大数据行业,像为某些机构做舆论监控的,他们用的却是Java。

  2. 接口:判断未来go语言是趋势,但看有没有具体轮子吧,Java or go ?

  3. app: flutter作为跨平台首选毕竟以前用过rn真的不好用,但flutter在iOS上架长期会有不稳定因素(说不定哪天被拒),安卓是没问题的,或者用flutter做成模块被iOS调用进行混合开发也行。

  4. 小程序: uni-app吧,全平台小程序:微信、头条、支付宝。

  5. web前端:vue了。

资料

极客时间-架构实战案例解析

SaaS ERP和传统ERP的区别在哪里?

Iass、Pass、SasS三种云服务区别

erp-pro

适合SaaS的几种架构比较

查了一下资料

VIPER View-Interactor-Presenter-Entity-Router

View

  • 提供完整的视图,负责视图的组合、布局、更新
  • 向Presenter提供更新视图的接口
  • 将View相关的事件发送给Presenter

Presenter

  • 接收并处理来自View的事件
  • 向Interactor请求调用业务逻辑
  • 向Interactor提供View中的数据
  • 接收并处理来自Interactor的数据回调事件
  • 通知View进行更新操作
  • 通过Router跳转到其他View

Router(路由)

  • 提供View之间的跳转功能,减少了模块间的耦合
  • 初始化VIPER的各个模块

Interactor(交互器)

  • 维护主要的业务逻辑功能,向Presenter提供现有的业务用例
  • 维护、获取、更新Entity
  • 当有业务相关的事件发生时,处理事件,并通知Presenter

Entity(实体)

  • 和Model一样的数据模型

VIPER把MVC中的Controller进一步拆分成了Presenter、Router和Interactor。和MVP中负责业务逻辑的Presenter不同,VIPER的Presenter的主要工作是在View和Interactor之间传递事件,并管理一些View的展示逻辑,主要的业务逻辑实现代码都放在了Interactor里。Interactor的设计里提出了”用例”的概念,也就是把每一个会出现的业务流程封装好,这样可测试性会大大提高。而Router则进一步解决了不同模块之间的耦合。

demo

ok!!那就按照上面的意思来写个 demo 呗~~

前言

RBAC(Role-Based Access Control )基于角色的访问控制。

casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。

gorm-adapter使用这个库,Casbin可以从Gorm加载政策支持的数据库或保存政策。

理解casbin的使用

具体可以看这篇文章:Basic Role-Based HTTP Authorization in Go with Casbin(中文翻译为在 Go 语言中使用 casbin 实现基于角色的 HTTP 权限控制),具体demo我也加了详细注释。

这里有几个需要弄懂的:

模型文件的配置auth_model.conf

1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
  • Model CONF 至少应包含四个部分:[request_definition], [policy_definition], [policy_effect], [matchers]

  • 如果 model 使用 RBAC, 还需要添加[role_definition]部分。

  • sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)

  • 更具体的可以直接看官方文档

策略文件policy.csv

1
2
3
4
p, admin, /*, *
p, anonymous, /login, *
p, member, /logout, *
p, member, /member/*, *
  • admin 角色可以访问所有内容
  • member 角色可以访问以 /member/ 开头的路径和 logout 路径
  • 未认证用户可以登陆

gorm-adapter

在上个个例子中,策略文件就是一个简单的 csv 文件,描述了哪些角色可以访问哪些路径等。但在实际项目中策略文件一般都会存储在数据库,这时候就用到了gorm-adapter

直接看官方给出的demo

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
package main

import (
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v2"
_ "github.com/go-sql-driver/mysql"
)

func main() {

//初始化一个Gorm adapter 并在Casbin enforcer中使用它:
//Gorm adapter会使用一个名叫casbin的MySQL数据库
//如果不存在,将会自动创建
//或者通过 gormadapter.NewAdapterByDB(gormInstance)读取一个已经存在的数据库

a, _ := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")
e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a)

// Or you can use an existing DB "abc" like this:
// The adapter will use the table named "casbin_rule".
// If it doesn't exist, the adapter will create it automatically.
// a := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/abc", true)



e.LoadPolicy()//从数据库加载策略


e.Enforce("alice", "data1", "read")// 检查许可

// 更改策略
// e.AddPolicy(...)
// e.RemovePolicy(...)


e.SavePolicy()//保存策略
}

实际项目举例

rbac_model.conf模型文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && ParamsMatch(r.obj,p.obj) && r.act == p.act

qmplus.sql表的定义并通过sql往数据库添加数据

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
/*
Navicat Premium Data Transfer

Source Server : qmplus
Source Server Type : MySQL
Source Server Version : 50644
Source Host : localhost:3306
Source Schema : qmplus

Target Server Type : MySQL
Target Server Version : 50644
File Encoding : 65001

Date: 15/04/2020 17:48:50
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for casbin_rule
-- ----------------------------
DROP TABLE IF EXISTS `casbin_rule`;
CREATE TABLE `casbin_rule` (
`p_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v0` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v1` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v2` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v3` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v4` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v5` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of casbin_rule
-- ----------------------------
INSERT INTO `casbin_rule` VALUES ('p', '8881', '/base/login', 'POST', '', '', '');
...

更新Casbin规则

1
2
3
4
5
6
7
8
func UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error {
var cs []model.CasbinModel
err := global.GVA_DB.Table("casbin_rule").Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Find(&cs).Updates(map[string]string{
"v1": newPath,
"v2": newMethod,
}).Error
return err
}

其中GVA_DB就是全局定义的gorm.DB实例

1
2
3
4
var (
GVA_DB *gorm.DB
...
)

资料

RBAC用户、角色、权限、组设计方案
casbin 基于角色的访问控制