django 添加数据库comment的方法

使用django迁移工具创建数据库是不支持设置comment的, 但是我们可以修改源码, 使django支持将字段的verbose_name值作为数据库字段的comment

点开django源码中的文件: django/db/backends/base/schema.py, 找到 方法def column_sql(self, model, field, include_default=False):, 添加如下两行:

# .....
    elif field.unique:  // 这是源码中已经存在
        sql += " UNIQUE"  // 这是源码中已经存在的
    if field.verbose_name:  // 这是新增的行
        sql += " COMMENT '{}'" .format(field.verbose_name)  // 这是新增的行
# ...
  • 注意, 使用mysql中测试过, sqlite测试不行, 其他的可以自己测, 欢迎评论反馈

python elasticseach quickStart

几个快速入门小例子, 支持中文分词和拼音搜索. elastic Search 版本为: 6.7, docker-compose 地址为: https://github.com/sazima/docker-compose/tree/master/elastic_search_pinyin

创建索引index, 指定字段中文分词器和pinyin.

es = Elasticsearch()

es.indices.create('blog', body={
        "settings": {
            "number_of_shards": 3,
            "number_of_replicas": 1,
            "analysis": {
                "analyzer": {
                    "default": {
                        "tokenizer": "ik_smart"
                    },
                    "pinyin_analyzer": {
                        "type": "custom",
                        "tokenizer": "my_pinyin",
                        "filter": ["word_delimiter"]
                    }
                },
                "tokenizer": {
                    "my_pinyin": {
                        "type": "pinyin",
                        "keep_first_letter": True,
                        "keep_separate_first_letter": True,
                        "keep_full_pinyin": True,
                        "keep_original": True,
                        "limit_first_letter_length": 16,
                        "lowercase": True
                    }
                }
            }
        }
    })

创建doc, 设置字段mapping

es.indices.put_mapping(index='blog', doc_type='article', body={
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "ik_max_word",
                "copy_to": True,
                "fields": {
                    "pinyin": {
                        "type": "text",
                        "term_vector": "with_positions_offsets",
                        "analyzer": "pinyin_analyzer",
                        "boost": 10
                    }
                }
            },
            "content": {
                "type": "text",
                "analyzer": "ik_max_word",
                "copy_to": True,
                "fields": {
                    "pinyin": {
                        "type": "text",
                        "term_vector": "with_positions_offsets",
                        "analyzer": "pinyin_analyzer",
                        "boost": 10
                    }
                }
            },
            "author": {
                "type": "text",
                "analyzer": "ik_max_word",
                "copy_to": True,
                "fields": {
                    "pinyin": {
                        "type": "text",
                        "term_vector": "with_positions_offsets",
                        "analyzer": "pinyin_analyzer",
                        "boost": 10
                    }
                }
            },
            "keyword": {
                "type": "text",
                "analyzer": "ik_max_word",
                "fields": {
                    "pinyin": {
                        "type": "text",
                        "term_vector": "with_positions_offsets",
                        "analyzer": "pinyin_analyzer",
                        "boost": 10
                    }
                }
            }}})

文档增删查

   es.create('blog', 'article', '2', {
        'title': '这是一个标题',
        'content': '这里是内容'
    })
    es.get('blog', 'article', 1)
    es.search('blog', 'article', {
        "query": {
            "multi_match": {
                "type": "best_fields",
                "operator": "and",
                "query": "zheshi",
                "fields": ["title", 'title.pinyin']
            }
        }})


[go]method的指针声明及非指针声明

以下大部分为搬运过程重写代码。原文:https://segmentfault.com/a/1190000003772144


method可以为一个type添加(声明)一个方法,例如:

type Cat struct {
}

func (c Cat) Hwo() {
    fmt.Println("Miah!")
}

即对Cat类型(结构体)添加Hwo方法,使其在叫唤的时候可以发出声音, 添加方法的代码表现比java好很多(extend),也比python好(需重新声明一个Class)。


按官方的spec可以对应到如上的例子的两种声明:

func (c Cat) Hwo()
func (c *Cat) Hwo()

两种有什么区别呢?

package main

import (
    "fmt"
)

type Cat struct {
    age int
}

func (c Cat) AddAge() {
    fmt.Println("add age!")
    fmt.Println(c.age + 10)
    c.age += 1
}

func (c *Cat) AddOneAge() {
    c.age += 1
    fmt.Println("add one age!")
}

func main() {
    cat := &Cat{1}
    fmt.Println(cat)
    cat.AddAge()
    fmt.Println(cat)
    cat.AddOneAge()
    fmt.Println(cat)
}

结果:

&{1}
add age!
11
&{1}
add one age!
&{2}

修改cat声明方式为:

cat := Cat{1}

结果:

{1}
add age!
11
{1}
add one age!
{2}

发生了什么?
1. cat变量是一个指针,可以用reflect.Typeof(cat)看出来;
2. (c Cat)添加的方法AddAge()被执行了,能获取cat的值,但是未改变cat指针指向的内存区块的值;
3. (c *Cat)添加的方法AddOneAge()被执行了,改变cat指针指向的内存区块的值;
4. 重新定义catb := Cat{1},似乎catb非指针,但是还是一样的结果(除了变量部分)。

如何解读?
1. 无论是将一个变量声明为指针还是非指针,go在method上对待它们的态度都是一致的;
2. 声明method时,传入(c *Cat)的声明方式才能修改new出来的对象(cat :=),因为method的处理对象是一个Cat类型的指针。
3. 在声明变量时,建议声明为指针对象cat := &Cat{1},这样做有好处

a.传递指针有卓有成效的,特别是传递大型变量时
b.大部分科学的代码是传递指针,为了代码的一致性最好都用指针

详见Reference.3

题外话,这里有个例子可以阐明一个状况
对于interface来说,识别method时会辨别(c Cat)及(c *Cat)的区别: http://play.golang.org/p/-g44WHg_uT

Reference


  1. http://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/
  2. http://golang.org/ref/spec#Method_declarations
  3. http://golang.org/doc/faq#methods_on_values_or_pointers

golang中结构体的初始化方法(new方法)

1、自定义一个结构体

type Vertex struct {
    X, Y float64
}

2、初始化方法-指针:

rect1 := new(Vertex )
rect2 := &Vertex {}
rect3 := &Vertex {1, 2}
rect4 := &Vertex {X:100, Y:200}

注意: 这几个变量全部为指向Rect结构的指针(指针变量),因为使用了new()函数和&操作符.

3、初始化方法-类型实例

a := Rect{}
b := Rect{3, 4}
c := Rect{X=5, Y=6}

则表示这个是一个Rect{}类型.两者是不一样的.

4、区别
下面这个例子能展现之间区别:

package main
import "fmt"

type Vertex struct {
        X, Y float64
} 
func main() {
    rect1 := new(Vertex)
    rect2 := &Vertex{1, 2}
    fmt.Printf("%v  %T  %v \n",  rect1,  rect1,  *rect1)
    fmt.Printf("%v  %T  %v \n",  rect2,  rect2,  *rect2)

    rect3 := Vertex{X: 5, Y: 6}
    fmt.Printf("%v  %T\n",  rect3,  rect3)

}

// 输出:
/*
&{0 0}  *main.Vertex  {0 0} 
&{1 2}  *main.Vertex  {1 2} 
{5 6}  main.Vertex
*/

从结果中可以清楚的看到两者的不同.

用 new 分配内存 内建函数 new 本质上说跟其他语言中的同名函数功能一样:new(T) 分配了零值填充的 T 类型的内存空间,并且返回其地址,一个 *T 类型的值。用 Go 的术语说,它返回了一个指针,指向新分配的类型 T 的零值。记住这点非常重要。 这意味着使用者可以用 new 创建一个数据结构的实例并且可以直接工作。

务必记得 make 仅适用于 map,slice 和 channel,并且返回的不是指针。应当用 new获得特定的指针。

原文: http://fuhao715.github.io/2014/03/25/golang-struct-init-new.html

frp内网穿透加nginx 反向代理

目的: 将站点部署到外网无法访问的树莓派中.

部署wordpress

可使用 lnmp 部署, 也可以使用 docker, 树莓派3B+不支持原版的 mysql docker 镜像. 故本次镜像使用: hypriot/rpi-mysql.

docker-compose 文件为:

version: '3.3'

services:
   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
       - /home/xxx/files/wwwroot/xxx:/var/www/html
     ports:
       - "81:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: xxx

   db:
     image: hypriot/rpi-mysql
     volumes:
       - /home/wukt/files/wordpress_db/:/var/lib/mysql
     ports:
       - "3306:3306"
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: xxx
       MYSQL_DATABASE: wordpress
       MYSQL_USER: xxx
       MYSQL_PASSWORD: xxx

frp 服务端和客户端

github: https://github.com/fatedier/frp
可在项目的 release 中下载响应的服务器和客户端版本, 具体配置方式可以参照文档, 本文记录本次部署配置.

服务端配置

服务端应配置的外网可以访问的服务器上.

[common]
bind_port = 8888
bind_addr = 0.0.0.0
bind_udp_port = 
kcp_bind_port = 
privilege_token = xxx
vhost_http_port = 88  ; 一般使用 http 即可, 因为浏览器到 nginx 可以走 https, 配置相对简单些.
vhost_https_port = 444
log_level = info
log_max_days = 3
max_pool_count = 20
tcp_mux = true
max_ports_per_client = 0
authentication_timeout = 900

客户端配置:

[common]
server_addr = ip  ; 服务器端公网ip
server_port = 8888  ; 与服务器端 bindport 相同.
privilege_token = xxx
protocol = tcp
use_encryption = true
use_compression = true
log_level = info
log_max_days = 3
tcp_mux = true
login_fail_exit = false

[raspberrypi]
type = http
local_port = 81
custom_domains = blog.wktadmin.com ; 多域名使用逗号隔开.

nginx 反向代理

如果不使用 nginx, 网站部署仍然是成功的, 但是为了网站可以使用80/443端口访问, 而又不影响服务端已存在的其他网站, 只好使用 nginx 反向代理, 将浏览器访问80/443端口的请求, 转发到 frp 的 http 服务监听的88端口上.

本站开启 https, 所以配置如下:

server
    {
    listen 443 ssl http2;
        #listen [::]:80;
        server_name blog.wktadmin.com;
            ssl_certificate /etc/letsencrypt/live/blog.wktadmin.com/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/blog.wktadmin.com/privkey.pem;
 location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass_header Server;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
                proxy_pass http://127.0.0.1:88/;
        }
    }

树莓派(Raspbian)安装docker-compose

依照官网提供的方法https://docs.docker.com/compose/install/, 会下载一个404的页面到/usr/local/bin下, 原因是系统不主流导致sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose指向了不存在的路径.

安装方法

sudo pip install docker-compose

但是直接pip会提示缺少依赖导致错误:

File "/usr/lib/python2.7/dist-packages/setuptools/command/easy_install.py", line 1145, in build_and_install         self.run_setup(setup_script, setup_base, args)       File "/usr/lib/python2.7/dist-packages/setuptools/command/easy_install.py", line 1133, in run_setup         raise DistutilsError("Setup script exited with %s" % (v.args[0],))     distutils.errors.DistutilsError: Setup script exited with error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1          ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-8KnQlf/pynacl/

安装依赖

sudo apt-get install -y  libffi-dev gcc libc-dev make

postgrepsql 添加自增列

表中已有数据, 需要填充:

如果没有id字段

alter table bandwidth_day_use add id serial not null;

如果有id字段

PostgreSQL中让主键自增长可先建立一个对应表的sequence

CREATE SEQUENCE test_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;

其中START是从数字几开始,INCREMENT BY是一次增长几个数字,NO MINVALUE是没有最小值,NO MAXVALUE是没有最大值;

然后修改表id字段

alter table test alter column id set default nextval('test_id_seq');