xia的小窩

一起來coding和碼字吧

0%

python-flask-db在shell的操作

這裡主要放點紀錄,關於增加、讀取、更新、刪除的部分

這邊假設都有一個Flask寫好的app.py,直接進到Flask shell需要一些前置作業。

1
2
3
# 這邊是 Windows 的環境下使用,mac 使用 export 取代 set 即可。
# set FLASK_APP="restdemo:create_app()"
$env:FLASK_APP="restdemo:create_app()"

那處理好之後,記得回到跟目錄

1
cd ..

接著運行一下程式

1
flask run

這邊沒問題後,看一下db的部分,也要將db初始化,這邊我就隨便丟一個create schema…喔,這邊不用和我的一樣,只是僅供參考。

1
2
3
4
5
class User(db.Model):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(64), unique = True)
password_hash = db.Column(db.String(128))
email = db.Column(db.String(64))

直接進行db初始化

1
2
3
flask db init # 初始化,產生 migration 資料夾
flask db migrate # 自動生成版本,監測table的變化,如果table減少一個字段,不生效
flask db upgrade # 升級

這邊要看一下migrations這個資料夾,instance這個資料夾應該會有個db。

這邊就準備進到sql的部分了

打開mysql cli,先查看資料表

1
show databases;

這邊可以看到你自己的幾個資料庫,先建立一個database起來。

1
2
mysql> create database demo;
Query OK, 1 row affected (0.00 sec)

給出OK之後呢,使用demo這張表,以及show這個table

1
2
3
4
mysql> use demo
Database changed
mysql> show tables;
Empty set (0.00 sec)

這邊沒問題後,使用python開始對這張表進行丟資料的動作,下載相關的庫。

1
pip install pymysql

接著,在app.py內去呼叫。

1
2
3
4
5
6
7
8
9
10
11
12
13
db = SQLAlchemy()
# ...
def create_app():
app = Flask(__name__)
api = Api(app)
# app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///demo.db"
# demo 是資料庫的名字。
app.config["SQLALCHEMY_DATABASE_URI"] = 'mysql+pymysql://root:你的密碼@localhost:3306/demo'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
migrate = Migrate(app, db)

return app

對接mysql

首先進入flask shell

1
2
3
(.env) PS C:\Users\rex09\Desktop\Flask-RestAPI\flask-rest-demo> flask shell
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32
App: restdemo

他會告訴你app和一些基本數據,這時候我們需要引入相關的資料,以我的為例:

1
2
3
4
5
6
7
>>> from restdemo import db, create_app
>>> db
# 他這邊返回的時候會把密碼給*掉。
<SQLAlchemy mysql+pymysql://root:***@localhost:3306/demo?charset=utf8mb4>
>>> app = create_app()
>>> app
<Flask 'restdemo'>

我們這邊就開始進入新增資料

1
2
3
4
5
6
>>> from restdemo.model.user import User
>>> u = User(username = "test", password_hash = "xyz", email = "test@test.com")
>>> u
<User (transient 2062256157408)>
>>> db.session.add(u)
>>> db.session.commit()

再來進入剛才的mysql cli

1
2
3
4
5
6
mysql> select * from user;
+----+----------+---------------+---------------+
| id | username | password_hash | email |
+----+----------+---------------+---------------+
| 1 | test | xyz | test@test.com |
+----+----------+---------------+---------------+

這時候就可以看見test這筆數據被新增進去了。

新增多筆的話,可以使用add_all()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
users_data = [
{"username": "user1", "password_hash": "user1", "email": "user1@user1.com"},
{"username": "user2", "password_hash": "user2", "email": "user2@user2.com"},
{"username": "user3", "password_hash": "user3", "email": "user3@user3.com"},
]

users = [User(username = data["username"],
password_hash = data["password_hash"],
email = data["email"]) for data in users_data]

# 加到 mysql
db.session.add_all(users)
# 提交到 mysqls
db.session.commit()

到了這邊,我就直接接著使用,不過username有更改過,不過一樣是mysqlshell

1
2
3
4
5
6
7
8
9
10
mysql> select * from user;
+----+----------+---------------+-----------------+
| id | username | password_hash | email |
+----+----------+---------------+-----------------+
| 1 | test | xyz | test@test.com |
| 2 | demo | demo | demo@demo.com |
| 3 | test1 | test1 | test1@test1.com |
| 4 | test2 | test2 | test2@test2.com |
+----+----------+---------------+-----------------+
4 rows in set (0.00 sec)

沒問題之後呢,使用query排找:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> users = db.session.query(User).all()
>>> users
[<User 1>, <User 2>, <User 3>, <User 4>]
>>> type(users)
<class 'list'>
>>> for u in users:
... print(u)
...
<User 1>
<User 2>
<User 3>
<User 4>
>>> type(users[0])
# 這裡會告訴你這個class的類別。
<class 'restdemo.model.user.User'>

那我們為了方便觀察,可以使用__repr__

1
2
3
4
5
6
class User(db.Model):
# ...
def __repr__(self) -> str:
return "id = {}, username = {}".format(
self.id, self.username
)

這時候我們再嘗試輸出

1
2
3
4
id = 1, username = test
id = 2, username = demo
id = 3, username = test1
id = 4, username = test2

如果說不想看這麼多的話,可以使用first()

1
2
3
>>> users = db.session.query(User).first()
>>> users
id = 1, username = test

如果說要找test的話。

1
2
3
4
5
6
7
>>> users = db.session.query(User).filter(User.username == 'test')
>>> type(users)
<class 'flask_sqlalchemy.query.Query'>
>>> for u in users:
... print(u)
...
id = 1, username = test

如果說有很多test,你只想找第一個

1
2
3
4
5
>>> users = db.session.query(User).filter(User.username == 'test').first()  
>>> type(users)
<class 'restdemo.model.user.User'>
>>> users
id = 1, username = test

如果是想要找內部有test的字串的話

1
2
3
4
5
6
7
8
9
>>> users = db.session.query(User).filter(User.username.like("%test%"))
>>> users
<flask_sqlalchemy.query.Query object at 0x00000162AE985330>
>>> for u in users:
... print(u)
...
id = 1, username = test
id = 3, username = test1
id = 4, username = test2

對資料做更新

這邊就是update的部分囉,一樣的概念

1
2
3
4
5
6
7
8
9
10
11
# 我們找 test1 做更新
>>> users = db.session.query(User).filter(User.username == 'test1').first()
>>> users
id = 3, username = test1
>>> users.password_hash
'test1'
>>> users.password_hash = "xyz123"
>>> users.password_hash
'xyz123'
>>> db.session.commit()
>>>

這邊再看一下mysql cli

1
2
3
4
5
6
7
8
9
10
mysql> select * from user;
+----+----------+---------------+-----------------+
| id | username | password_hash | email |
+----+----------+---------------+-----------------+
| 1 | test | xyz | test@test.com |
| 2 | demo | demo | demo@demo.com |
| 3 | test1 | xyz123 | test1@test1.com |
| 4 | test2 | test2 | test2@test2.com |
+----+----------+---------------+-----------------+
4 rows in set (0.00 sec)

對資料做刪除

刪除的話使用delete()

1
2
3
4
5
>>> users = db.session.query(User).filter(User.username == 'test1').first()
>>> users
id = 3, username = test1
>>> db.session.delete(users)
>>> db.session.commit()

這時候使用mysql cli

1
2
3
4
5
6
7
8
9
mysql> select * from user;
+----+----------+---------------+-----------------+
| id | username | password_hash | email |
+----+----------+---------------+-----------------+
| 1 | test | xyz | test@test.com |
| 2 | demo | demo | demo@demo.com |
| 4 | test2 | test2 | test2@test2.com |
+----+----------+---------------+-----------------+
3 rows in set (0.00 sec)

主要還是要看你的database的設置,要注意PRIMARY_KEY就行。