使用如下命令为 ubuntu 系统安装 virtualenv
sudo apt-get install python-virtualenv
当我们使用 virtualenv 命令创建虚拟环境时,默认使用的 python 解释器为 /usr/bin/python27(然后创建该解释器对应的副本),那么我们该如何指定解释器的版本呢?
使用参数 -p
$ sudo virtualenv -p ~/anaconda3/bin/python test
CentOS一些基础的知识
使用如下命令为 ubuntu 系统安装 virtualenv
sudo apt-get install python-virtualenv
当我们使用 virtualenv 命令创建虚拟环境时,默认使用的 python 解释器为 /usr/bin/python27(然后创建该解释器对应的副本),那么我们该如何指定解释器的版本呢?
使用参数 -p
$ sudo virtualenv -p ~/anaconda3/bin/python test
SQLAlchemy查询过滤器

SQLAlchemy查询执行函数

# coding=utf-8
from urllib import quote_plus as urlquote
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
import MySQLdb
用此方法链接可以指定UTF8编码,同时解决密码中含有特定字符,比如含有@,则把密码部分进行URL编码
echo=True 会显示每条执行的 SQL 语句
max_overflow 最大链接数
connstr = "mysql+mysqldb://root:%[email protected]:3306/dbname?charset=utf8" % urlquote('password')
engine = create_engine(connstr,echo=True,max_overflow=5)
metadata = MetaData()
user = Table('user', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(20)),
)
color = Table('color', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(20)),
)
metadata.create_all(engine)
conn = engine.connect()
#插入数据
engine.execute(
"INSERT INTO color( name) VALUES ('test');"
)
result = engine.execute('select * from color')
print(result.fetchall())
conn.execute(user.insert(),{'name':'test'})
sql = user.insert().values(name='test2')
conn.execute(sql)
#删除一条user表里的 条件是id大于1的
#sql = user.delete().where(user.c.id > 1)
#执行
#conn.execute(sql)
#更新
#把名字为test的修改为aaa
#sql = user.update().where(user.c.name == 'test').values(name='aaa')
#conn.execute(sql)
print "查询user表里的内容"
sql = select([user, ])
res =conn.execute(sql)
print res.fetchall()
print '查询user表下的id'
sql = select([user.c.id, ])
res =conn.execute(sql)
print res.fetchall()
print '查询user表和color表的name,条件是user表的id1=color的id1'
sql = select([user.c.name, color.c.name]).where(user.c.id==color.c.id)
res =conn.execute(sql)
print res.fetchall()
print '查询user表的name,并按照条件排序'
#按照名字排序
sql = select([user.c.name]).order_by(user.c.name)
res =conn.execute(sql)
print res.fetchall()
print '按照id排序'
sql = select([user.c.name]).order_by(user.c.id)
res =conn.execute(sql)
print res.fetchall()
print '查询user表的name,并按照条件分组'
sql = select([user]).group_by(user.c.name)
res =conn.execute(sql)
print res.fetchall()
#关闭链接
conn.close()
cookie是附加在http请求中的,tornado默认的set_cookie和get_cookie方法是明文不加密传输的,而set_secure_cookie和get_secure_cookie是明文加密传输的。代码见下:
import tornado.web
import tornado.ioloop
from tornado.options import define,options,parse_command_line
define('port',default=8888,help='run on the port',type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
if not self.get_secure_cookie('username'):
self.set_secure_cookie('username','littlethunder')
self.write('just set your cookie')
else:
a=self.get_secure_cookie('username')
print(a)
self.write('you have cookie before')
def main():
parse_command_line()
app=tornado.web.Application(
[(r'/',MainHandler)],
cookie_secret='abcde'
)
app.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
if __name__=='__main__':
main()
通过浏览器可以看到效果如下:

如果使用set_secure_cookie和get_secure_cookie方法,那么必须在tornado.web.Application中设置cookie_secret参数,’abcd’只是我测试写的,生产环境下可以用uuid生成一个随机字符串来用,但使用过程中要保证这个字符串恒定。 如果要用set_cookie和get_cookie方法,则只需把上面secure去掉,把cookie_secret参数也去掉即可,cookie就不截图了,是明文的。
最后总结一些cookie和secure_cookie的区别:cookie是基于session的,即打开浏览器设置cookie后,只要不关闭浏览器cookie会一直保存,关闭浏览器后cookie删除,其实就是保存在浏览器运行进程的那块内存中。secure_cookie是保存在硬盘中的cookie,过期时间为一个月,所以一旦设置secure_cookie后,不论浏览器关闭与否,只要不清空cookie,这个值就一直保存直到cookie过期失效。
之前答应过群里几个同学要晒下我们的Tornado项目结构,后来就忘了。。。今天晒出来。
无论是Tornado项目还是Django的项目,大体结构都是一样的。最外层是工程结构,包含了配置、文档、打包等信息,当然还有源码。
项目结构大体都是这样:
project
- conf/
- docs/
- src/
- package1/
- __init__.py
- models.py
- manager.py
- server.py
- setup.py
- MANIFEST.in
对于项目来说,只考虑两个问题,第一:本地开发是否方便;第二:线上部署是否方便。
Django的./manage.py runserver的方式对于本地开发调试就很方便,所以对于Tornado项目来说,也需要有一个类似的机制可以方便的在开发环境中启动项目。
因为我们是采用标准的PyPi包分发的方式部署的项目,所有项目文件最终都会落到site-packages中,所以包目录的规划就是个问题。
比如像Django那样,把所有的App作为独立的包分散到site-packages中,还是把源码目录”src”作为独立的包放到site-packages中。
两种不同的方式,在启动时也有所差别,因为包的路径是不一样的。这里不讨论哪种方式更合理,我们只说实际的使用情况。
所以部署方便的点在于,我把包放到site-packages中后是否能方便的启动项目。这意味着包的结构需要兼容本地启动和线上启动。
所以就扯到另外一个问题,本地启动项目时,你当前脚本所在的目录就是默认的包根目录,也就是在sys.path中会加入当前文件所在目录,也就是上面结构中的project/src。你要引用package1下的模块,直接from package1.models import xxxx即可。
而在线上的情况是,源码目录是作为独立包放在site-packages中的。你要引用的话需要from src.package1.models import xxx。
这种本地和线上不同引用的问题在Django中是没有的,除非你调整了Django的结构。
包的依赖路径问题,基本上都可以通过sys.path.insert()来解决。
两种解决的方式,一个是改线上的sys.path,一个是改本地的。线上的改动只需要在项目加载时把src目录先insert到sys.path中,作为一个新的根路径。
另外一个就是改本地的启动命令,把src所在的目录加到sys.path中。
从个人的习惯来说,能调整本地逻辑的就不去修改部署环境的逻辑,让其按照默认的方式处理是最稳当的方式。毕竟线上挂了影响很大。
所以我会在本地启动项目是做上面的处理,同时所有包的引用触发是同包的情况下,否则都需要从src开始,也就是:from src.package1.models import xx 。
project
├── MANIFEST.in
├── README.md
├── conf
│ └── supervisord.conf
├── fabfile
│ ├── __init__.py
├── requirements.txt
├── setup.cfg
├── setup.py
└── project_src
├── __init__.py
├── handlers
│ ├── __init__.py
│ ├── base.py
│ ├── index.py
├── server.py
├── settings
│ ├── __init__.py
│ ├── base.py
│ └── develop.py
├── templates
│ └── base.html
├── url.py
└── models
├── __init__.py
├── model1.py
└── model2.py
其中一server.py的示例代码如下:
#!/usr/bin/env python
import os
import sys
from logging.config import dictConfig
from importlib import import_module
import click
import tornado.ioloop
import tornado.web
from raven.contrib.tornado import AsyncSentryClient
def make_app(debug=None):
from project_src.url import urls
assert isinstance(urls, (list, tuple)), 'urls must be list or tuple'
return tornado.web.Application(urls, debug=debug)
def init_log():
dictConfig(tornado.settings.LOGGING)
@click.command()
@click.option('--port', default=9090)
@click.option('--profile', default='develop')
def serve(port, profile):
settings = import_module(f'project_src.settings.{profile}')
tornado.settings = settings
init_log()
app = make_app(settings.DEBUG)
app.listen(port)
app.sentry_client = AsyncSentryClient(
'<sentry>'
)
sys.stdout.write(f"Start server at:http://0.0.0.0:{port} nProfile: {profile}n")
tornado.ioloop.IOLoop.current().start()
if __name__ == "__main__":
current_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, current_path)
serve()
其实无论哪种方式,只要能够保证大家保有共识就可以,比如the5fire不去修改线上的加载路径,目的是避免有人去按照常识去修改包目录之后产生不可预知的后果。
在使用SQLALchemy更新数据的时候,一直不成功。
数据更新的方式采用ajax,具体代码如下:
$(function () {
$('#user_profile').click(function (event) {
event.preventDefault(); //prevent the actual form post
user_profile();
});
// Inject our CSRF token into our AJAX request.
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", $('#csrf_token').val())
}
}
})
})
function user_profile() {
$.ajax({
type: $('#tab_1_1 form').attr("method"),
url: $('#tab_1_1 form').attr("action"),
data: $('#tab_1_1 form').serialize(),
contentType: "application/x-www-form-urlencoded",
success: function (data) {
console.log(data);
}
});
}
但是提交到后台无法获取数据,提交的数据结构如下所示:
csrf_token=IjkwNjQ5OTE2MTJjMGMwZDk4OTc5ZmQxOTZjOTgxMmU4MmU0ZDRmMzAi.DjHgiQ.hDgD-Yz89RkJZPL-YorWJdG7Z7c&fullname=%E9%BB%84%E5%85%B5&nick_name=%E7%8B%AC%E8%A1%8C%E4%BE%A0&phone_number=13429950072&about_me=%E6%88%91%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AE%85%E7%94%B7%EF%BC%8C%E8%AF%B7%E5%A4%A7%E5%AE%B6%E4%B8%8D%E8%A6%81%E6%89%93%E6%89%B0%E6%88%91%E7%BB%A7%E7%BB%AD%E5%AE%85%E3%80%82&website_url=https%3A%2F%2Fpdf-lib.org
之后看一下后台如何接收数据:
# 验证提交
if form.validate_on_submit():
current_user.fullname = form.fullname.data
current_user.phone_number = form.phone_number.data
current_user.nick_name = form.nick_name.data
current_user.website_url = form.website_url.data
try:
sql_query=str(db.session.add(current_user._get_current_object()))
print(sql_query)
print(current_user._get_current_object())
db.session.commit()
except:
flash('账户更新失败!')
flash('账户资料已更新!')
使用这种方式无法获取数据,数据一直没有更新,搞不清是什么情况。之后不断调试,参考了别人文章之后终于把问题解决了。
需要修改源代码如下:
# 验证提交
if form.validate_on_submit():
current_user.fullname = request.values.get('fullname', 0)
current_user.phone_number = request.values.get('phone_number', 0)
current_user.nick_name = request.values.get('nick_name', 0)
current_user.about_me = request.values.get('about_me', 0)
current_user.website_url = request.values.get('website_url', 0)
try:
db.session.add(current_user._get_current_object())
db.session.commit()
except:
flash('账户更新失败!')
flash('账户资料已更新!')
这个是flask获取post参数的方式,具体可以参考这里: https://pdf-lib.org/Home/Details/5201
这样再次获取数据就没有什么问题了。
再次使用SQLALchemy保存数据,数据已经成功更新了。
在flask项目中,Session, Cookies以及一些第三方扩展都会用到SECRET_KEY值,这是一个比较重要的配置值。
在使用flask时,我产生了这个错误:the session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret
解决方法是在flask项目开头加入设置SECRET_KEY。
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456'
# or
app.secret_key = '123456'
# or
app.config.update(SECRET_KEY='123456')
如果需要设置一个随机的SECRET_KEY值。我们可以使用os模块的urandom函数来获得随机值。
>>> import os
>>> os.urandom(24)
'xeewxe4xc0xeexb1]x9bxa0x9e)x15Qhemxe5xf17xd6xceBxb7xb4'
应用程序需要24小时不间断运行。这时可使用supervisor监控应用程序的进程。当发生应用程序内部错误退出、进程被杀死等情况时,自动重启应用程序。
supervisor由python写成, 简单好用。官方网站 http://supervisord.org,上面有详细的指南文档。
1)安装 setuptools
$sudo apt-get install python-setuptools
2) 使用easy_install安装 supervisor
$sudo easy_install supervisor
安装完成后出现:
/usr/bin/supervisord --supervisor服务守护进程
/usr/bin/supervisorctl--supervisor服务控制程序
以下命令可以将配置文件示例打印到控制台:
$ echo_supervisord_conf
若要生成配置文件,使用命令:
$ sudo echo_supervisord_conf > /etc/supervisord.conf
或者在当前目录生成:
$ echo_supervisord_conf > supervisord.conf
Notice: 如何停止子进程
场景:如果supervisord.conf中配置的command是执行一个bash,而bash里执行java,那么当使用supervisorctl stop [programname]停止程序时,只有上层进程被停止,而java进程没有被停止。
解决办法:
在配置文件中设置:
stopasgroup=true
killasgroup=true
在上面生成的配置文件后,追加:
[program:helloworld]
command=./helloworld ;执行命令
process_name=%(program_name)s
autostart=true ; 程序是否随supervisor启动而启动
autorestart=true ;程序停止时,是否自动重启
startsecs=10
$ supervisord -c supervisord.conf
1)开启/停止某个程序
# supervisorctl [start | stop] [program名称] //在supervisord.conf中定义的
2)查看进程状态
$supervisorctl status
配置文件中配置:
[inet_http_server] ; inet (TCP) server disabled by default
port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
那么可以从浏览器通过访问 localhost:9001来查看进程状态
1)将supervisord.conf拷贝到 /etc 目录下
2)启动脚本 supervisord.sh (centos/redhat)
#!/bin/sh
#
# /etc/rc.d/init.d/supervisord
#
# Supervisor is a client/server system that
# allows its users to monitor and control a
# number of processes on UNIX-like operating
# systems.
#
# chkconfig: - 64 36
# description: Supervisor Server
# processname: supervisord
# Source init functions
. /etc/rc.d/init.d/functions
prog="supervisord"
prog_bin="/usr/local/bin/supervisord"
PIDFILE="/tmp/supervisord.pid"
start()
{
echo -n $"Starting $prog: "
# Source init functions
. /etc/rc.d/init.d/functions
prog="supervisord"
prog_bin="/usr/local/bin/supervisord"
PIDFILE="/tmp/supervisord.pid"start()
{
echo -n $"Starting $prog: "
daemon $prog_bin --pidfile $PIDFILE
[ -f $PIDFILE ] && success $"$prog startup" || failure $"$prog startup"
echo
}
stop()
{
echo -n $"Shutting down $prog: "
[ -f $PIDFILE ] && killproc $prog || success $"$prog shutdown"
echo
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $prog
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
;;
esac
3)添加为系统服务
# mv supervisord.sh /etc/init.d/supervisord
# chkconfig --add supervisord
# chkconfig --level 345 supervisord on
4) 开启/停止服务
# service supervisord [start | stop]
对于logkit-pro这样的服务,我们推荐使用supervisor作为守护进程进行管理,这样即使程序由于某种原因异常关闭,还能通过supervisor自动重启。
logkit-pro在设计上保证了即使异常重启也保证数据不会丢失,最坏情况是意外中断后重启导致出现部分数据重复,正常情况都是不重不漏发送
Supervisor是用Python开发的Linux/Unix系统下的一个进程管理工具。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外终止,supervisor监听到进程不存活时,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写脚本来控制。
如果您的机器已经安装了 supervisor,可以跳过这一步。
supervisor 是 python 编写的,所以机器上首先要安装 python,一般的 Linux 发行版都已经自带 python 了。
supervisor 官方推荐的安装方式,第一种是使用 easy_install 工具安装。
所以如果您机器上没有easy_install,需要先安装一下。
安装 easy_install
wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py -O - | sudo python
通过easy_install安装supervisor
easy_install supervisor
Ubuntu用户安装supervisor
只需执行如下命令:
sudo apt-get install supervisor
安装完成后,supervisor的主配置文件一般存放在 /etc/supervisor/supervisord.conf
打开可以看到
[include]
files = /etc/supervisor/conf.d/*.conf
会监听 /etc/supervisor/conf.d/ 下的配置文件。
如果没有这个主配置文件,你就要创建一个/etc/supervisor文件夹,然后用如下命令生成
echo_supervisord_conf > /etc/supervisor/supervisord.conf
根据实际情况对supervisor的配置文件做修改。
也可以将下列配置文件手动写入到 /etc/supervisor/supervisord.conf 中。
; supervisor config file
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0700 ; sockef file mode (default 0700)
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP)
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket
; The [include] section can just contain the "files" setting. This
; setting can list multiple files (separated by whitespace or
; newlines). It can also contain wildcards. The filenames are
; interpreted as relative to this file. Included files *cannot*
; include files themselves.
[include]
files = /etc/supervisor/conf.d/*.conf
修改配置文件后,重启下supervisord
service supervisord restart
如果service中没有supervisord,参考文档https://serverfault.com/questions/96499/how-to-automatically-start-supervisord-on-linux-ubuntu
至此,supervisor守护进程已经安装完毕。
我们假设logkit已经下载并解压缩到 /home/qiniu/logkit-pro/ 目录下,并包含了运行所需的所有文件,如下所示。
$ ls /home/qiniu/logkit-pro/
auths.conf logkit-pro logkit-pro.conf public
我们编写配置文件 logkit_supervisor.conf 并放置到 /etc/supervisor/conf.d/ 目录,编写的配置内容如下所示。
[program:logkit-pro]
command=/home/qiniu/logkit-pro/logkit-pro -f /home/qiniu/logkit-pro/logkit-pro.conf
directory=/home/qiniu/logkit-pro/
priority=999
autostart=true
startsecs=3
stopwaitsecs=200
autorestart=true
user=qiniu
redirect_stderr=true
log_level=info
stdout_logfile=/home/qiniu/logkit-pro/logkit-pro.log
stdout_logfile_maxbyte=200MB
stdout_logfile_backups=2
其中
配置完成后,我们要让supervisor载入当前的新配置,执行如下命令:
supervisorctl reread
supervisor感知到新配置后,我们就可以将logkit-pro加入到管理中,执行如下命令:
supervisorctl add logkit-pro
然后程序就已经正常运行了,可以通过supervisor查看
supervisorctl status
通过supervisor停止、启动、重启的命令如下:
supervisorctl stop logkit-pro
supervisorctl start logkit-pro
supervisorctl restart logkit-pro
详细的命令可以参考supervisor的官方文档
根据我们的supervisor配置,logkit-pro的日志存放在
/home/qiniu/logkit-pro/logkit-pro.log
而supervisor本身的日志可以在supervisor的主配置文件中查看
cat /etc/supervisor/supervisord.conf
默认情况下存放在
/var/log/supervisor/supervisord.log
假设postgresql安装位置

然后,使用dos窗口
进入这个位置
![]()
导入(本地和默认端口可以不用属性)
psql -d 数据库名 -h ip地址 -p 数据库端口 -U 用户名 -f 文件地址

完成

知识只有共享才能传播,才能推崇出新的知识,才能学到更多,这里写的每一篇文字/博客,基本都是从网上查询了一下资料然后记录下来,也有些是原滋原味搬了过来,也有时加了一些自己的想法