簡說Python之flask-SQLAlchmey的web應用
阿新 • • 發佈:2020-03-18
[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!!