2018-10-31 更新Logging日志记录以及异常捕获
感谢廖大教程。Python实战
直接在闲置的服务器上开发。阿里云Centos 6.8 64位
。
1 搭建开发环境
Python 环境是Python 3.4
, 在装aiohttp的时候报错,之前用pip3和系统本身的pip(Python 2.7
)也有安装问题,索性下最新版Python 3.6.4
,并安装virtualenv独立运行。
python3.3以后自带venv模块支持轻量级虚拟环境,virtualenv模块仍然支持,可安装。
1.创建虚拟环境
virtualenv --no-site-packages myvenv
等价于
virtualenv myvenv (目前新版默认不使用系统环境包)
python3自带venv
python -m venv myvenv
也是默认全新干净的环境,相反可选的参数
python -m venv --system-site-packages myvenv
使虚拟环境指向系统环境包目录(非复制),在系统环境pip新安装包,在虚拟环境就可以使用。
2.激活虚拟环境
Platform Shell Command to activate virtual environment
Posix bash/zsh $ source <venv>/bin/activate
fish $ . <venv>/bin/activate.fish
csh/tcsh $ source <venv>/bin/activate.csh
Windows cmd.exe C:> <venv>\Scripts\activate.bat
PowerShell PS C:> <venv>\Scripts\Activate.ps1
3.关闭虚拟环境
deactivate
4.删除虚拟环境
删除目录即可
-by 林er爱喝果汁Q https://www.liaoxuefeng.com/discuss/001409195742008d822b26cf3de46aea14f2b7378a1ba91000/00150035599472221b683bc9ae245c4a08097bd0cc7866c000
所以直接运行:
> python3.6 myvenv
> source myvenv/bin/activate
之后就可以直接用Python命令而非Python3.6来指定使用版本了。
2 编写Web App骨架
原文中监听127.0.0.1:9000,本地测试直接打开即可,可是服务器怎么看页面呢。安装有nginx,但是配置太麻烦。想要快速查看页面。
服务器直接访问
阿里ECS管理页面中有公网和私网IP
在代码中重新监听私有IP的9000端口,然后访问公网IP:9000,无效。
将端口加入到安全组
之后,再次访问公网IP:9000。就成功了,不过是下载的形式。加上Content-Type即可:
return web.Response(body=b'Awesome', headers={'content-type':'text/html'})
ERROR: address already in use
用Ctrl+Z
结束正在运行的Python进程后,再次python app.py
出错
error while attempting to bind on address ('172.*.*.*', 9000): address already in use
原因和解决办法
在ubuntu下,这个问题通常由于按ctrl+z结束程序造成。使用fg命令之后,按ctrl+c重新结束任务即可。
CTRL-Z和CTRL-C都是中断命令,但是他们的作用却不一样.
CTRL-C是强制中断程序的执行,
而CTRL-Z的是将任务中断,但是此任务并没有结束,他仍然在进程中他只是维持挂起的状态,用户可以使用fg/bg操作继续前台或后台的任务,fg命令重新启动前台被中断的任务,bg命令把被中断的任务放在后台执行.
例如:
当你vi一个文件是,如果需要用shell执行别的操作,但是你又不打算关闭vi,因为你得
存盘推出,你可以简单的按下CTRL-Z,shell会将vi进程挂起~,当你结束了那个shell操作之后,你可以用fg命令继续vi你的文件.
-by http://blog.csdn.net/helinbin/article/details/56015572
用了fg
之后,确实又启动可以访问了:),用Ctrl+C
结束后再次运行就没有地址占用错误提醒了。
##### 弃坑
3节ORM 和 5节的Web框架。都比较难。而且对比GIT中的多个不明所以的函数后面的继续不下去了。虽然很想粗略的过一遍。但是算了,承认自己比较弱也是和自己的一种妥协。协程和装饰器还是理解的慢。以后再来补,一个月后再来挑战。 2018-3-1 17:48:24
##### 再次开始
2018年9月17日
服务器再次清零(试过好多东西,内部git、laravel、练手的php框架),重新安装Python,只当作Python工具服务器用,只用Python实现,比如,想做一个距离懂你课程的倒计时来用退款鼓励自己。
`腾讯云Centos 7.5 64位`
总之,现在做什么事情,就是要快!
网上各种资料一查,就必须要尽快搞定。
我也总是目标不明确,本来做A,中途遇到问题牵扯到的其他问题就都看了,其实目标只是A。A才是主线,其他的都不重要。
3. 编写ORM
安装MariaDB、连接以及系统一些问题花费了小半天,遇到问题不少,如果刚开始就从手册走的话,就会清晰便捷很多。MariaDB使用MySQL连接器。
1). 非异步的ORM
#! /usr/bin/python
import pymysql as DB
import datetime
from hashlib import md5
class Sql(object):
def __init__(self):
pass
def sqlInit(self, dbInfo, mode='tuple'):
""" sql初始化 """
try:
dbHost = dbInfo.get('host')
dbUser = dbInfo.get('user')
dbPasswd = dbInfo.get('passwd')
dbName = dbInfo.get('db')
conn = DB.connect(host=dbHost, user=dbUser, passwd=dbPasswd, db=dbName)
if mode == 'tuple':
cur = conn.cursor()
else:
cur = conn.cursor(DB.cursors.DictCursor)
return conn, cur
except Exception as e:
self.log(e)
print("connect failed.")
exit()
@classmethod
def query(cls, sql, mode='tuple', **dbInfo):
""" 查询 """
conn, cur = cls().sqlInit(dbInfo, mode)
try:
cur.execute(sql)
data = cur.fetchall()
except Exception as e:
Sql.log(e)
Sql.log("error sql: " + str(sql))
data = None
conn.close()
return data
@classmethod
def insert(cls, sql, param, **dbInfo):
""" 插入 """
conn, cur = cls().sqlInit(dbInfo)
try:
cur.executemany(sql, param)
conn.commit()
result = True
except Exception as e:
conn.rollback()
Sql.log(e)
Sql.log("error sql: " + str(sql))
result = False
conn.close()
return result
@classmethod
def delete(cls, sql, param, **dbInfo):
""" 删除 """
conn, cur = cls().sqlInit(dbInfo)
try:
cur.execute(sql, param)
conn.commit()
result = True
except Exception as e:
Sql.log(e)
Sql.log('error sql: ' + str(sql))
conn.rollback()
result = False
conn.close()
return result
@classmethod
def update(cls, sql, param, **dbInfo):
""" 更新 """
conn, cur = cls().sqlInit(dbInfo)
try:
cur.execute(sql, param)
conn.commit()
result = True
except Exception as e:
Sql.log(e)
Sql.log('error sql: ' + str(sql))
conn.rollback()
result = False
conn.close()
return result
@classmethod
def run(cls, sql, **dbInfo):
""" 执行其他语句 """
conn, cur = cls().sqlInit(dbInfo)
try:
cur.execute(sql)
result = True
except Exception as e:
Sql.log(e)
Sql.log('error sql: ' + str(sql))
result = False
conn.close()
return result
@staticmethod
def log(msg):
""" 记录日志 """
nowStr = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
fileName = datetime.datetime.now().strftime('%Y%m%d') + '.log'
with open('./' + fileName, 'a') as f:
f.write(str(nowStr) + '\n')
if isinstance(msg, Exception):
f.write("\tFile: %s, Line: %s.\n" % (msg.__traceback__.tb_frame.f_globals['__file__'], msg.__traceback__.tb_lineno))
f.write('\t' + str(msg) + '\n')
dbInfo = {
'host': '127.0.0.1',
'user': 'root',
'passwd': '123456',
'db': 'test_xxxx'
}
try:
print("1. 建表")
if not Sql.run("DROP TABLE IF EXISTS `user`", **dbInfo):
raise Exception('drop error')
sql = '''
CREATE TABLE `user`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`password` varchar(64) NOT NULL,
`created` varchar(64) NULL,
`updated` varchar(64) NULL,
`deleted` varchar(64) NULL,
`status` int(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`)
) ENGINE = InnoDB;
'''
if not Sql.run(sql, **dbInfo):
raise Exception('建表失败!')
print('2. 插入')
sql = "INSERT INTO `user`(name, password, created, status) VALUES (%s, %s, %s, %s)"
param = [['admin', md5(b'123456').hexdigest(), datetime.datetime.now(), 1]]
Sql.insert(sql, param, **dbInfo)
print('3. 查询')
data = Sql.query("select * from user", 'tuple', **dbInfo)
print(data)
print('4. 更新')
Sql.update("UPDATE `user` set name = %s, updated = %s where id = %s", ('admin2', datetime.datetime.now(), 1), **dbInfo)
data = Sql.query("select * from user", 'dict', **dbInfo)
print(data)
print('5. 删除')
Sql.delete("DELETE FROM `user` where id = %s", 1, **dbInfo)
data = Sql.query("select * from user", 'tuple', **dbInfo)
print(data)
except Exception as e:
print('error: '+str(e))
执行结果
1. 建表
2. 插入
3. 查询
((1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', '2018-10-04 21:52:13.543246', No
ne, None, 1),)
4. 更新
[{'id': 1, 'name': 'admin2', 'password': 'e10adc3949ba59abbe56e057f20f883e', 'crea
ted': '2018-10-04 21:52:13.543246', 'updated': '2018-10-04 21:52:13.553830', 'dele
ted': None, 'status': 1}]
5. 删除
()
用了两种查询方法tuple dict.
def cursor(self, cursor=None):
"""
Create a new cursor to execute queries with.
:param cursor: The type of cursor to create; one of :py:class:`Cursor`,
:py:class:`SSCursor`, :py:class:`DictCursor`, or :py:class:`SSDictCursor`.
None means use Cursor.
"""
if cursor:
return cursor(self)
return self.cursorclass(self)
有一个简单日志记录错误。整体很简单粗糙,不能称之为ORM,只是简单的增删改查操作。
2).异步的ORM
照着廖大的抄了一遍,再看了justoneliu的ORM注释理解了一下没懂的地方。
还有需要修改的地方,比如Logging.info输出如何输出log文件,输出中args丢失,更新数据未指定列全部成了默认值。不影响主进度日志待定,先完善一下输出。
4. 编写Model
Model小节也简单过了一遍,应该有个生成脚本直接通过各表Model去生成sql。
5. 编写WEB框架
这里感觉也好难理解呢。python之aiohttp源码解析——add_route和middleware的工作方式 ,aiohttp的middleware为啥有两个参数,倒序的包含handle又是怎么回事?还是没有理解。官方文档aiohttp middlewares中都用了@web.middleware
修饰了,大概看一下流程,以后再来搞懂吧。真头大,每次看到这些很难懂的都感觉自己很笨。
6. 配置
配置我直接复制重命名.bak了一份,开发时自己去掉就好了。
7. 编写MVC
希望可以顺利启动哈哈。orm webframe app 都很紧张呢。
这里终于要建handlers.py
了,之前app.py运行会报错
INFO:root:Model into metaclass ,yeeeeeeeeee
DEBUG:asyncio:Using selector: EpollSelector
INFO:root:create database connection pool...
./app.py:107: DeprecationWarning: loop argument is deprecated
logger_factory, response_factory
INFO:root:init jinja2...
INFO:root:set jinja2 template path: /data/webapp/templates
Traceback (most recent call last):
File "./app.py", line 118, in <module>
loop.run_until_complete(init(loop))
File "/usr/local/lib/python3.7/asyncio/base_events.py", line 568, in run_until_complete
return future.result()
File "./app.py", line 111, in init
add_routes(app, 'handlers')
File "/data/webapp/webFrame.py", line 169, in add_routes
mod = __import__(module_name, globals(), locals())
ModuleNotFoundError: No module named 'handlers'
Ok
8. 构建前端
blogs = [
Blog(id='1', name='Test Blog', summary=summary, created_at=time.time()-120),
Blog(id='2', name='Something New', summary=summary, created_at=time.time()-3600),
Blog(id='3', name='Learn Swift', summary=summary, created_at=time.time()-7200)
]
这块没理解,调了几次发现只是因为Blog(dict)继承自dict, 就直接转为dict了。Ohhhhhhh
本节没有按照原文用uikit css框架,直接写一个最简单的html,用一个jquery cdn就够用了。类似这个很像文档的文章,我想要的博客就是这样的,简单不做作,有干货,虽然我还差好多