結合我們822實驗室開源的圖像處理平臺(http://822lab.top)介紹Flask後端開發,供後續學弟學妹參考,整個平臺的從零搭建記錄在[這裏](https://www.jianshu.com/p/d92a53d57ab1),後端倉庫在[這裏](https://gitee.com/happysunrise/lab822server),前端倉庫在[這裏](https://gitee.com/happysunrise/lab822),歡迎大家爲平臺做貢獻。
Flask是一個python web微框架,也是剛開始接觸,入門服務器端框架並能快速搭建好一個簡單的服務器端程序是有套路的,當然,服務器開發並不那麼簡單,是需要持續更新的,到底好不好,還有哪些地方需要重構需要加強,是需要把爛項目放到線上跑一跑才知道的。
快速入門和搭建簡單服務器端的套路如下:
- 找到文檔中的hello world demo
- 看如何接收http請求(路由)
- 看如何連接數據庫
- 看如何部署
如果不是前後端分離的應用,則還需要看:
- 靜態文件管理
找到文檔中的hello world demo
框架的官方網站一定都有文檔,一般user guide裏都能找到hello world demo。
Flask的英文版文檔在這裏,中文版在這裏,其實文檔都已經寫的非常全了,這裏會結合平臺的需求寫一下實現。
- 安裝
Linux或Mac都有系統自帶的python,但是不建議把依賴都裝在系統中,如果玩壞了系統可能就癱了,而且每個項目的依賴都不一樣,因此建議在電腦上安裝Anaconda或者virtualenv,它們都可以爲每個項目創建一個虛擬環境,在環境內安裝所需要的依賴,這種環境管理遷移之類的都很方便。Anaconda直接到官網下載,virtualenv安裝如下:
pip install virtualenv
然後創建一個項目環境,進入到環境並安裝依賴。
- Anaconda
#創建環境 conda create -n py2 python=2.7 # py2替換爲自己的環境名稱 #激活環境 source activate py2 # windows不用加source #安裝依賴 conda install Flask #或者用pip,如: pip install Flask #退出環境 source deactivate # windows不用加source
- virtualenv
#創建環境 mkdir myproject cd myproject python3 -m venv venv py -3 -m venv venv #windows #在老版本的 Python 中要使用下面的命令創建虛擬環境: virtualenv venv #在 Windows 下: \Python27\Scripts\virtualenv.exe venv #激活相應環境: . venv/bin/activate #在 Windows 下: venv\Scripts\activate # 安裝依賴 pip install Flask # 退出環境 deactivate
- 在pycharm中創建一個Flask項目
創建好後會看到
直接點箭頭運行,在http://127.0.0.1:5000/就可以看到hello world。
如果開啓debug模式,則將app.run()
改爲app.run(debug=True)
。
看如何接收http請求(路由)
跑起來hello world就說明安裝之類的不存在問題了,下面就需要看路由和http方法如何接收。
一般會看
- url怎麼綁定
- 帶變量的url怎麼解析
- HTTP方法怎麼接收
hello world的例子中,前端的請求url是http://127.0.0.1:5000/
,最後一個/
對應@app.route('/')
,如果想請求http://127.0.0.1:5000/hello
出現hello world,則將@app.route('/')
改爲@app.route('/hello')
。
@app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello, World'
帶有變量的url怎麼解析呢
@app.route('/user/<username>') def show\_user\_profile(username): # show the user profile for that use return 'User %s' % username @app.route('/post/<int:post\_id>') def show\_post(post\_id): # show the post with the given id, the id is an intege return 'Post %d' % post\_id
HTTP方法怎麼接收呢
一般前後端通信約定的數據格式都是json,服務器端返回json需要用jsonify()
,如果是post請求,需要獲取請求體,可以用json.loads(request.get\_data())
,如下例:
POST請求爲
- url: /imgproc/lab
- request:
{ operations: [{ code: 'string', params: [], image: 'string' }] }
- response:
{ result: 1, message: { image:'string', log: 'string' } }
代碼爲
@app.route('/imgproc/lab', methods=['GET', 'POST']) def img\_proc\_lab(): if request.method == 'GET': messages = [{'type':1, subType:2},{'type':2, subType:3}] return jsonify({'result': 1, 'message': messages}) else: request\_body = json.loads(request.get\_data()) operation = request\_body['operations'][0] o\_code = operation['code'] o\_params = operation['params'] image\_base64 = request\_body['image'] """do something""" message = dict({'image': 'base64\_data', 'log': 'log'}) return jsonify({'result': 1, 'message': message})
flask連接mongodb數據庫
項目使用的數據庫是mongodb,通過mongoengine連接數據,需要先安裝mongoengine,文檔在這裏
pip install flask-mongoengine
然後在app創建語句後加入下面代碼:
from flask\_mongoengine import MongoEngine app.config['MONGODB\_SETTINGS'] = { 'db': 'lab822', 'host': '127.0.0.1', 'port': 27017 } db = MongoEngine(app)
在另一個文件中寫數據庫的model,更多的字段類型可以查看文檔
from app import db class ImgOperation(db.Document): name = db.StringField(required=True) code = db.StringField(required=True) type = db.ListField(db.EmbeddedDocumentField('ImgType')) params = db.ListField(db.EmbeddedDocumentField('ImgParam')) class ImgType(Document): name = StringField(required=True) class ImgParam(Document): type = StringField(required=True) name = StringField(required=True) value = ListField() limit = StringField() pName = StringField()
數據的增刪查改操作代碼如下:
- 增:
type = ImgType(name='圖像平滑').save()
- 查:
type = ImgType.objects(name='圖像平滑')
- 改:
改操作需要先查詢再修改
ImgType.objects(name="圖像平滑").update(name='形態學處理')
- 刪:
ImgType.delete()
如何部署
我選擇部署到gunicorn上,很簡單,但是當時找資料也是花了很大功夫。需要做以下操作。
- 分離app.run()語句
最好將app.py分爲app.py和run.py,新建一個python package,名爲app,在__init__.py中粘貼app.py的代碼,把`if __name__ == '__main__':
app.run(debug=True)`一句放在run.py裏,調試和本地可以用run.py啓動服務器,部署時候就不用了。
最後run.py的內容爲:
from app import app if \_\_name\_\_ == '\_\_main\_\_': app.run(debug=True)
app package的__init.py__文件內容爲:
app = Flask(\_\_name\_\_) """some config""" if \_\_name\_\_ != '\_\_main\_\_': gunicorn\_logger = logging.getLogger('gunicorn.error') #設置logge app.logger.handlers = gunicorn\_logger.handlers app.logger.setLevel(gunicorn\_logger.level)
- 到服務器上進到項目目錄,運行下面語句:
gunicorn -w 4 -b 0.0.0.0:5000 --logger-level=debug --error-file ../error.log app:app