在开发客户端的时候总是需要网络请求的,之前用过java的,node的,感觉都不是非常的方便。再加上机器学习越来越火,索性就用python来开发下web。
python的主流web框架有django和flask,这里使用了flask。flask是python编写的轻量级 Web 应用框架。
数据库的命令行简单操作:
mongo
> show dbs
admin 0.078GB
config 0.078GB
local 0.078GB
todoApp 0.078GB
> use todoApp
switched to db todoApp
> show collections
accounts
device
device1
system.indexes
user
> db.user.find()
{ "_id" : ObjectId("5a4874bd377863486d2bbd62"), "name" : "test1", "password" : "123456" }
{ "_id" : ObjectId("5a487b143778634acfa46901"), "name" : "test2", "password" : "123456", "device" : ObjectId("5a43a35e37786301612a7b33"), "devices" : [ ObjectId("5a43a35e37786301612a7b33"), ObjectId("5a43a36937786301612a7b34"), ObjectId("5a43a37f37786301752f889c"), ObjectId("5a45ce5a3778631d5636391f") ], "emdevices" : [ { "_id" : ObjectId("5a43a35e37786301612a7b33"), "devicename" : "device1", "macaddr" : "00:11:22:33:44:55" }, { "_id" : ObjectId("5a43a36937786301612a7b34"), "devicename" : "device1", "macaddr" : "00:11:22:33:44:55" }, { "_id" : ObjectId("5a43a37f37786301752f889c"), "devicename" : "device1", "macaddr" : "00:11:22:33:44:55" }, { "_id" : ObjectId("5a45ce5a3778631d5636391f"), "devicename" : "test3", "macaddr" : "00:11:22:33:44:55" } ] }
> db.device.find()
{ "_id" : ObjectId("5a41e13337786350a4d19faf"), "_updated" : ISODate("2017-12-26T05:42:11Z"), "devicename" : "test1", "macaddr" : "00:11:22:33:44:55", "_created" : ISODate("2017-12-26T05:42:11Z"), "_etag" : "b3fd2a4b62fc803529a5315a25ed7777e1c6229e" }
{ "_id" : ObjectId("5a41e2a237786350c4876f7d"), "_updated" : ISODate("2017-12-26T05:48:18Z"), "devicename" : "test2", "macaddr" : "11:11:22:33:44:55", "_created" : ISODate("2017-12-26T05:48:18Z"), "_etag" : "3dee3f048406c5eb5a591164ea9a4b5e2f6c2309" }
{ "_id" : ObjectId("5a41e2aa37786350c4876f7e"), "_updated" : ISODate("2017-12-26T05:48:26Z"), "devicename" : "test3", "macaddr" : "22:11:22:33:44:55", "_created" : ISODate("2017-12-26T05:48:26Z"), "_etag" : "ed88bc3d176d7645782ab2bcc7c30536d221f425" }
{ "_id" : ObjectId("5a41e35c377863510233e7ca"), "_updated" : ISODate("2017-12-26T05:51:24Z"), "devicename" : "test1", "macaddr" : "12:11:22:33:44:55", "_created" : ISODate("2017-12-26T05:51:24Z"), "_etag" : "04a2bf47976ff6dfce3447ca8ea18fcefd8025ae" }
利用python的pip需要安装flask, mongengine等。
先看下整个工程的目录结构,分为app,controllers和models。类似于mvc,其中view在这里还没有,主要是一些api,view的工作都是给客户端来实现的。
.
├── app
│ └── __init__.py
├── config.json
├── controllers
│ ├── __init__.py
│ ├── tasks.py
│ └── users.py
├── models
│ ├── device.py
│ ├── __init__.py
│ └── user.py
└── run.py
init.py是初始化的使用用到的。这里是创建了flask,主要在controller中使用,以及创建了mongodb,在models中使用。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask
from flask_mongoengine import MongoEngine
app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {
'db': 'todoApp',
'host': '127.0.0.1',
'port': 27017
}
#app.config.from_pyfile('config.json')
db = MongoEngine(app)
#数据库对应的模型
#import models
#api的业务逻辑
import controllers
先看下device,这里定义了两个字段,一个devicename,一个macaddr。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import db
# 类名定义 collection
class Device1(db.Document):
# 字段
devicename = db.StringField()
macaddr = db.StringField()
def __str__(self):
return "devicename:{} - macaddr:{}".format(self.devicename, self.macaddr)
再看下User模型,首先这里定义了name,password和phone几个简单的字段,就不多讲了。
然后定义了device,devices以及emdevices。ReferenceField表示一个引用,最终会引用上述定义的device模板中的实际的数据库数据。而EmbeddedDocumentField则会把实际的数据存入到User中。举个例子,如果device的devicename为“test”。然后devices和emdevices中都可以找到device并且他的名字为"test"。而当把device的表中的devicename改为“test_change”。那么在devices中只是用了引用,所以devicename也改为了“test_change”,而emdevices则还是"test"。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import db
from models.device import Device1
# 类名定义 collection
class User(db.Document):
# 字段
name = db.StringField(max_length=30, required=True)
password = db.StringField(max_length=30, min_length=6, required=True)
phone = db.StringField()
device = db.ReferenceField(Device1)
devices = db.ListField(db.ReferenceField(Device1))
emdevices = db.ListField(db.EmbeddedDocumentField('Device1'))
def __str__(self):
return "name:{} - phone:{}".format(self.name, self.phone)
这里定义了两个接口,一个是POST的“/todo/api/v1/user”接口,用来保存user字段信息。一个是GET的“/todo/api/v1/user”接口,用来获取当前的user接口的信息,比较简单。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import app
from flask import Flask, jsonify, request, abort
from datetime import datetime
from models.user import User
from models.device import Device1
@app.route('/todo/api/v1/user', methods=['GET'])
def get_user():
devices = Device1.objects().all()
print devices
user = User.objects(name="test2").first()
print user
#user.update(device=device)
#user.update(devices=devices)
#print device.devicename
#user.update(emdevices=devices)
return jsonify({'userinfo': User.objects.all()}), 201
@app.route('/todo/api/v1/user', methods=['POST'])
def create_user():
if not request.json or not 'name' in request.json or not 'password' in request.json:
print(request)
abort(400)
user = User(name=request.json['name'], password=request.json['password']).save();
return jsonify({'userinfo': User.objects.all()}), 201
python run.py
接着可以通过postman来测试接口。可以的话,就可以在客户端使用网络请求了。
nginx反向代理,因为python flask默认的是ip:127.0.0.1,端口5000,所以需要反向代理到我们的服务器上,这样对应域名就可以使用了。
server {
listen 3000; # 监听3000端口
location / {
proxy_pass http://127.0.0.1:5000; # 代理本机127.0.0.1:5000的服务
}
location /static {
#alias /home/ubuntu/myproject/myblog/app/static; # 负载均衡
}
}
关于nginx怎么设置这里就不一一介绍了。
使用gunicorn在多核服务器上,为了支持更多的并发访问并充分利用资源,可以使用更多的 gunicorn 进程。
supervisor是一个用 Python 写的进程管理工具,可以很方便的用来在linux系统下启动、重启(自动重启程序)、关闭进程(不仅仅是 Python 进程)。
在/etc/supervisor/conf.d/目录下新建test.config文件,配置如下
[program:Test]
command=/usr/local/bin/gunicorn -c /etc/gunicorn/gun.conf --chdir /todoApp run:app
supervisorctl 一些命令:
help # 查看帮助
status # 查看程序状态
stop program_name # 关闭 指定的程序
start program_name # 启动 指定的程序
restart program_name # 重启 指定的程序
tail -f program_name # 查看 该程序的日志
上述配置只需要执行:
supervisorctl start Test
就可以在后台启动进程了。
基本上这样就可以搭建一个简单的restful的server了。当然结合上jwt(java web token)则更好点。这个就后续扩展吧。
代码可以参考: github中的例子
更完整的项目:极客Go云监工服务端