1. 程式人生 > >簡說Python之flask-SQLAlchmey的web應用

簡說Python之flask-SQLAlchmey的web應用

[TOC] 系統環境:`Ubuntu 18.04.1 LTS` Python使用的是虛擬環境:`virutalenv` Python的版本:`Python 3.6.9` ## 原生語句操作MySQL資料庫 ### 1.安裝MySQL ``` zsd@zsd-virtual-machine:~$ sudo apt-get install mysql-server libmysqlclient-dev -yq ``` 安裝PyMySQL[為python3可以驅動MySQL使用] ``` (zsdpy1) zsd@zsd-virtual-machine:~$ pip install PyMySQL ``` ### 2.MySQL設定使用者和許可權 ```sql root@zsd-virtual-machine:~# sudo mysql -uroot mysql> create database zsd; mysql> create user 'zsd'@'localhost' identified by 'zsd'; mysql> use zsd; Database changed mysql> grant all on zsd.* to 'zsd'@'localhost'; Query OK, 0 rows affected (0.00 sec) ``` ### 3.用PyMySQL操縱MySQL資料庫 1.db配置python ```python (zsdpy1) $ cat dbconfig.py # coding=utf-8 HOSTNAME = 'localhost' DATABASE = 'zsd' USERNAME = 'zsd' PASSWORD = 'zsd' DB_URI = 'mysql+pymysql://{}:{}@{}:3306/{}?charset=utf8'.format( USERNAME, PASSWORD, HOSTNAME, DATABASE) ``` * HOSTNAME:代表主機名, * DATABASE:代表建立的資料庫名稱 * USERNAME:進入mysql資料庫的使用者名稱 * PASSWORD:進入mysql的密碼 * DB_URI:用於PyMySQL驅動MySQL資料庫的uri。 ```python (zsdpy1) $ cat ex_db01.py # coding=utf-8 import pymysql from dbconfig import HOSTNAME, DATABASE, USERNAME, PASSWORD try: con = pymysql.connect(HOSTNAME, USERNAME, PASSWORD, DATABASE) cur = con.cursor() cur.execute("SELECT VERSION()") ver = cur.fetchone() print ("Database version : %s " % ver) except MySQLdb.Error as e: print ("Error %d: %s" % (e.args[0], e.args[1])) exit(1) finally: if con: con.close() ``` 上述的程式含義: * `pymysql.connect`,建立一個MySQL資料庫的連線。 * `con.cursor()`,建立一個遊標,可以通過SQL語句,操作MySQL資料庫的表和資料。 * `cur.execute`,執行一條SQL語句。 * ` ver = cur.fetchone()`,返回第一行資料 可以看到,這裡是用於返回資料庫的版本資料。 執行效果如下: ```python (zsdpy1) $ python ex_db01.py Database version : 5.7.29-0ubuntu0.18.04.1 ``` ### 4. CRUD增,刪,改,查 ```python (zsdpy1) $ cat curd3x.py # coding=utf-8 import pymysql from dbconfig import HOSTNAME, DATABASE, USERNAME, PASSWORD con = pymysql.connect(HOSTNAME, USERNAME, PASSWORD, DATABASE) with con as cur: cur.execute('drop table if exists users') cur.execute('create table users(Id INT PRIMARY KEY AUTO_INCREMENT, ' 'Name VARCHAR(25))') cur.execute("insert into users(Name) values('xiaoming')") cur.execute("insert into users(Name) values('wanglang')") cur.execute('select * from users') rows = cur.fetchall() for row in rows: print (row) cur.execute('update users set Name=%s where Id=%s', ('ming', 1)) print ('Number of rows updated:', cur.rowcount) cur = con.cursor(pymysql.cursors.DictCursor) cur.execute('select * from users') rows = cur.fetchall() for row in rows: print (row['Id'], row['Name']) ``` 程式解釋: 唯一的區別可以看到通過呼叫`cur.execute`,實現你想呼叫的任何SQL語句,如`drop table`,`insert`,`update`,`select`,`create table`等基礎SQL語句。 ## 使用SQLAlchemy ### 1.安裝SQLAlchemy ``` pip install SQLALchemy ``` 各種資料庫驅動介面,案例如下: ``` pymysql mysql+pymysql://:@/[?] MySQL-Python mysql+mysqldb://:@[:]/ cx_Oracle oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] ``` 實驗環境是`Python3.6`+`pymysql`,所以用的是第一個。 所以上述的`dbconfig.py`是一個基礎指令碼,公用的。 ### 2.原生SQL呼叫SQLAlchemy ```python (zsdpy1) $ cat SQLAlchemy_raw_sql3x.py # coding=utf-8 from sqlalchemy import create_engine from dbconfig import DB_URI eng = create_engine(DB_URI) with eng.connect() as con: con.execute('drop table if exists users') con.execute('create table users(Id INT PRIMARY KEY AUTO_INCREMENT, ' 'Name VARCHAR(25))') con.execute("insert into users(name) values('zsd')") con.execute("insert into users(name) values('lzh')") rs = con.execute('select * from users') for row in rs: print (row) ``` 其中 * `eng = create_engine(DB_URI)`,建立一個驅動引擎,用於連線MySQL資料庫 * `from dbconfig import DB_URI`,呼叫了`dbconfig.py`的變數:DB_URI 的資料. 呼叫的結果: 可以看到,我插入的兩條資料,`zsd`和`lzh` ```python (zsdpy1)$ python SQLAlchemy_raw_sql3x.py (1, 'zsd') (2, 'lzh') ``` ### 3.ORM ```python (zsdpy1) $ cat orm_sql.py # coding=utf-8 from sqlalchemy import create_engine, Column, Integer, String, Sequence from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import and_, or_ from sqlalchemy.orm import sessionmaker from dbconfig import DB_URI eng = create_engine(DB_URI) Base = declarative_base() class User(Base): __tablename__ = 'users' # id是主鍵,且給與一個Sequence,自增 id = Column(Integer, Sequence('user_id_seq'), primary_key=True, autoincrement=True) # name是string型別 name = Column(String(50)) # 刪除表,個人實驗環境,測試用。 Base.metadata.drop_all(bind=eng) Base.metadata.create_all(bind=eng) # 建立一個session,提供事務控制。 Session = sessionmaker(bind=eng) session = Session() # 新增資料,由於id的主鍵和自增的。所以合理只需新增name的值。 session.add_all([User(name=username) for username in ('zsd', 'lzh', 'huke','ly')]) # 資料庫的事務提交,commit session.commit() # 獲得結果的呼叫方法 def get_result(rs): print ('-' * 20) # 變數結果集內的name資料 for user in rs: print (user.name) #查詢所有的資料 rs = session.query(User).all() get_result(rs) # 相當於select * from user where id =2 rs = session.query(User).filter(User.id.in_([2, ])) get_result(rs) # 相當於select * from user where id >2 and id <4 rs = session.query(User).filter(and_(User.id > 2, User.id < 4)) get_result(rs) # 相當於select * from user where id =2 and id = 4 rs = session.query(User).filter(or_(User.id == 2, User.id == 4)) get_result(rs) # 相當於select * from user where name like '%s%' rs = session.query(User).filter(User.name.like('%s%')) get_result(rs) # 相當於select * from user where name ='zsd'的第一條資料 user = session.query(User).filter_by(name='ly').first() get_result([user]) ``` 效果如下: ``` (zsdpy1) $ python orm_sql.py -------------------- zsd lzh ly huke -------------------- lzh -------------------- ly -------------------- lzh huke -------------------- zsd -------------------- ly ``` ## 運用flask-SQLAlchmey ### 1.安裝Flask-SQLAlchemy ``` pip install Flask-SQLAlchemy ``` ### 2.flask-SQLAlchmey的web應用 核心的四個檔案如下: ```shell (zsdpy1) $ ls -l total 16 -rw-r--r-- 1 zsd zsd 552 3月 17 16:24 app_with_sqlalchemy.py -rw-r--r-- 1 zsd zsd 128 3月 17 16:24 config.py -rw-r--r-- 1 zsd zsd 198 3月 17 16:24 dbconfig.py -rw-r--r-- 1 zsd zsd 249 3月 17 16:24 users.py ``` * ` dbconfig.py`是常用配置檔案,上述已經解釋過了。 `users.py` ```python (zsdpy1) $ cat users.py # coding=utf-8 from ext import db class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50)) def __init__(self, name): self.name = name ``` 其中的含義: * ` from ext import db` ext存放了Flask第三方的擴充套件,通過db,傳導了`db.Model`。也體現了`ORM`中`model`。 * `id`是db模型中的列(Column),`Integer`型別.主鍵,自增id。 * `name`是db模型中的列(Column),`name`型別。 * `__init__`基礎語法,用於name的初始化。 `config.py` ``` (zsdpy1) zsd@zsd-virtual-machine:~/web_develop/chapter3/section3$ cat config.py # coding=utf-8 from dbconfig import DB_URI DEBUG = True SQLALCHEMY_DATABASE_URI = DB_URI SQLALCHEMY_TRACK_MODIFICATIONS = False ``` 繼承`dbconfig`裡面的常量,然後可以讓flak app去依賴。 `app_with_sqlalchemy.py` ```python (zsdpy1) zsd@zsd-virtual-machine:~/web_develop/chapter3/section3$ cat app_with_sqlalchemy.py # coding=utf-8 from flask import Flask, request, jsonify from ext import db from users import User app = Flask(__name__) app.config.from_object('config') db.init_app(app) with app.app_context(): db.drop_all() db.create_all() @app.route('/users', methods=['POST']) def users(): username = request.form.get('name') user = User(username) db.session.add(user) db.session.commit() return jsonify({'id': user.id}) if __name__ == '__main__': app.run(host='0.0.0.0', port=9000) ``` 其中程式的含義: * `from ext import db` 依賴db。 * `app.config.from_object('config')`獲取`config`中的常量URI * `app.app_context()`app發生請求之前,做一些操作,這裡是刪除user表中所有的資料。 * `@app.route('/users', methods=['POST'])`以post的方式,獲取name引數,後面新增user.nam資料到資料庫user表中。 ### 3.實驗操作 開啟flask app應用 ```python (zsdpy1) $ python app_with_sqlalchemy.py * Serving Flask app "app_with_sqlalchemy" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on * Running on http://0.0.0.0:9000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 177-062-521 ``` 我這裡編寫了一個http form post的指令碼,用於呼叫這個app應用。 ```python (zsdpy1) zsd@zsd-virtual-machine:~/web_develop/chapter3/section3$ cat http_form.py # -*- coding:utf-8 -*- import requests url = "http://0.0.0.0:9000/users" data = {"name":"zsd2"} res = requests.post(url=url,data=data) print(res.text) ``` 開始呼叫: ``` (zsdpy1) zsd@zsd-virtual-machine:~/web_develop/chapter3/section3$ python http_form.py { "id": 1 } ``` 可以看到返回了json串,id=1 檢視資料庫的資料,如下: ``` mysql>
select * from users; +----+------+ | id | name | +----+------+ | 1 | zsd2 | +----+------+ 1 row in set (0.00 sec) ``` 發現,`zsd2`的資料已經插入,至此,實驗結束。enjoy!!