python框架之Flask基礎篇(二)-------- 數據庫的操作


1.flask連接數據庫的四步:

  1. 倒入第三方數據庫擴展包:from flask_sqlalchemy import SQLAlchemy
  2. 配置config屬性,連接數據庫:

    app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@localhost/first_flask"
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

  3. 創建數據庫first_flask
  4. 創建操作數據庫對象:db = SQLAlchemy(app)

下面直接上代碼解釋:

 

# -*- coding:utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# url的格式為:數據庫的協議://用戶名:密碼@ip地址:端口號(默認可以不寫)/數據庫名
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@localhost/first_flask"
# 動態追蹤數據庫的修改. 性能不好. 且未來版本中會移除. 目前只是為了解決控制台的提示才寫的
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 創建數據庫的操作對象
db = SQLAlchemy(app)


class Role(db.Model):

    __tablename__ = "roles"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(16),unique=True)
    # 給Role類創建一個uses屬性,關聯users表。
    # backref是反向的給User類創建一個role屬性,關聯roles表。這是flask特殊的屬性。
    users = db.relationship('User',backref="role")
    # 相當於__str__方法。
    def __repr__(self):
        return "Role: %s %s" % (self.id,self.name)


class User(db.Model):
    # 給表重新定義一個名稱,默認名稱是類名的小寫,比如該類默認的表名是user。
    __tablename__ = "users"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(16),unique=True)
    email = db.Column(db.String(32),unique=True)
    password = db.Column(db.String(16))
    # 創建一個外鍵,和django不一樣。flask需要指定具體的字段創建外鍵,不能根據類名創建外鍵
    role_id = db.Column(db.Integer,db.ForeignKey("roles.id"))

    def __repr__(self):
        return "User: %s %s %s %s" % (self.id,self.name,self.password,self.role_id)


@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    # 刪除所有的表
    db.drop_all()
    # 創建表
    db.create_all()

    ro1 = Role(name = "admin")
    # 先將ro1對象添加到會話中,可以回滾。
    db.session.add(ro1)
    
    ro2 = Role()
    ro2.name = 'user'
    db.session.add(ro2)
    # 最后插入完數據一定要提交
    db.session.commit()

    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=ro1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id)
    us5 = User(name='tang', email='tang@itheima.com', password='158104', role_id=ro2.id)
    us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id)
    us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id)
    us8 = User(name='liu', email='liu@itheima.com', password='867322', role_id=ro1.id)
    us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id)
    us10 = User(name='sun', email='sun@163.com', password='235523', role_id=ro2.id)
    db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10])
    db.session.commit()
    app.run(debug=True)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面插播一條bug:

當把表格創建完成,注釋這兩句話:

 # 刪除所有的表
    db.drop_all()
    # 創建表
    db.create_all()

然后向表格里面插入數據,此時會出現這樣的錯誤:

sqlalchemy.exc.IntegrityError: (_mysql_exceptions.IntegrityError) (1062, "Duplicate entry 'admin' for key 'name'") [SQL: u'INSERT INTO roles (name) VALUES (%s)'] [parameters: ('admin',)]

查了網上的好多資料說把字段的約束unique=True去掉就好了,但是根本原因不在這。

原因就是因為app.run(debug=True)。開啟debug模式之后,當我們修改代碼的時候,比如將刪除表和創建表這兩句話注釋,然后打開插入數據的注釋。這個過程debug模式默認就已經把程序運行一遍了。此時數據庫就已經有了數據,當我們再次手動執行的時候,又往數據庫中插入了一條數據,這時候就會報錯。因為字段的約束是唯一性的unique,所以解決的辦法有兩種:

第一種:就是不要將刪除表和創建表這兩句話注釋,每次執行都要帶着這兩個句話。無論是debug模式自動執行還是我們手動執行程序,都會先刪除表然后再創建表,所以執行多少次都不怕。

第二種:關閉debug模式。就是這樣app.run()

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2.數據庫的增刪改查:

1.以下的方法都是返回一個新的查詢,需要配合執行器使用。

filter(): 過濾,功能比較強大。
filter_by():過濾,用在一些比較簡單的過濾場景。

order_by():排序。默認是升序,降序需要導包:from sqlalchemy import * 。然后引入desc方法。比如order_by(desc("email")).按照郵箱字母的降序排序。

 

group_by():分組。

2.以下都是一些常用的執行器:配合上面的過濾器使用。

get():獲得id等於幾的函數。比如:查詢id=1的對象。get(1)。切記:括號里沒有“id=”,直接傳入id的數值就ok。因為該函數的功能就是查詢主鍵等於幾的對象。

all():查詢所有的數據。

first():查詢第一個數據。

count():返回查詢結果的數量。

paginate():分頁查詢,返回一個分頁對象。paginate(參數1,參數2,參數3)

參數1:當前是第幾頁,參數2:每頁顯示幾條記錄,參數3:是否要返回錯誤。

返回的分頁對象有三個屬性:items:獲得查詢的結果,pages:獲得一共有多少頁,page:獲得當前頁。

3.常用的邏輯符:

需要倒入包才能用的有:from sqlalchemy import * 

not_  and_  or_   還有上面說的排序desc。

常用的內置的有:in_      表示某個字段在什么范圍之中。

4.其他關系的一些數據庫查詢:

endswith():以什么結尾。

startswith():以什么開頭。

contains():包含

5.下面體會一下上面的這些用法:

1. 查詢所有用戶數據 User.query.all() 2. 查詢有多少個用戶 User.query.count() 3. 查詢第1個用戶 User.query.first() 4. 查詢id為4的用戶[3種方式] User.query.get(4) User.query.filter_by(id=4).first()     User.query.filter(User.id==4).first() filter:(類名.屬性名==) filter_by:(屬性名=) filter_by: 用於查詢簡單的列名,不支持比較運算符 filter比filter_by的功能更強大,支持比較運算符,支持or_、in_等語法。 5. 查詢名字結尾字符為g的所有數據[開始/包含] User.query.filter(User.name.endswith('g')).all() User.query.filter(User.name.contains('g')).all() 6. 查詢名字不等於wang的所有數據[2種方式] from sqlalchemy import not_
注意了啊:邏輯查詢的格式邏輯符_(類屬性其他的一些判斷) User.query.filter(not_(User.name
=='wang')).all() User.query.filter(User.name!='wang').all() 7. 查詢名字和郵箱都以 li 開頭的所有數據[2種方式] from sqlalchemy import and_ User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all() User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all() 8. 查詢password是 `123456` 或者 `email` 以 `itheima.com` 結尾的所有數據 from sqlalchemy import or_ User.query.filter(or_(User.password=='123456', User.email.endswith('itheima.com'))).all() 9. 查詢id為 [1, 3, 5, 7, 9] 的用戶列表 User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all() 10. 查詢name為liu的角色數據 關系引用 User.query.filter_by(name='liu').first().role.name 11. 查詢所有用戶數據,並以郵箱排序 排序 User.query.order_by('email').all() 默認升序 User.query.order_by(desc('email')).all() 降序 12. 查詢第2頁的數據, 每頁只顯示3條數據 help(User.query.paginate) 三個參數: 1. 當前要查詢的頁數 2. 每頁的數量 3. 是否要返回錯誤 pages = User.query.paginate(2, 3, False) pages.items # 獲取查詢的結果 pages.pages # 總頁數 pages.page # 當前頁數

 3.使用第三方擴展框架遷移數據庫文件。

使用框架需要配置的代碼如下:

# -*- coding:utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy  # 操作數據庫的擴展包
from flask_script import Manager  # 用命令操作的擴展包
from flask_migrate import Migrate,MigrateCommand  # 操作數據庫遷移文件的擴展包

app = Flask(__name__)
app.debug = True
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@localhost/second_flask"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

db = SQLAlchemy(app)
manager = Manager(app)
# 創建遷移對象
migrate = Migrate(app,db)
# 將遷移文件的命令添加到‘db’中
manager.add_command('db',MigrateCommand)


class Role(db.Model):
    __tablename__ = "table_roles"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(16),unique=True)
    info = db.Column(db.String(100))
    Users = db.relationship("User",backref='role')


class User(db.Model):
    __tablename__ = "table_users"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(16),unique=True)
    info = db.Column(db.String(200))
    role_id = db.Column(db.Integer,db.ForeignKey("table_roles.id"))




@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':

    manager.run()

 

使用遷移命令如下:

比如上面的代碼所在的文件名稱為database.py。

1.python database.py db init    生成管理遷移文件的migrations目錄

2.python database.py db migrate -m "注釋"   在migrations/versions中生成一個文件,該文件記錄數據表的創建和更新的不同版本的代碼。

3.python database.py db upgrade  在數據庫中生成對應的表格。

4.當需要改表格的時候,改完先執行第二步,然后再執行第三步。

5.需要修改數據表的版本號的時候需要做的操作如下:

python database.py db upgrade 版本號  向上修改版本號

python database.py db downgrade 版本號   向下修改版本號

可能用到的其他的語句:

python database.py db history    查看歷史版本號

python database.py db current   查看當前版本號

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM