flask之數據庫的交互


一:關系型數據庫 mysql

  Flask-SQLAlchemy管理關系型數據庫。

  mysql數據庫引擎:url : mysql://username:passowrd@hostname/database

  安裝相關依賴包

    pip install flask-sqlalchemy

    pip install flask-mysqldb  如果使用mysql數據庫需要安裝這個依賴包

  數據庫連接配置

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest"  # 配置數據庫的鏈接
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True  # 請求結束后自動提交數據庫的變動
app.config['SQLALCHEMY_ECHO'] = True # 執行后顯示原始sql語句

db = SQLAlchemy(app)

@app.route("/user")
def user():
    pass

if __name__ == '__main__':
    app.run()

 

 

二:數據庫模型 orm

  object-relationship-map 對象關系映射,簡答說:就是通過創建實例對象==相當於在數據庫中映射了一張表。

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest"
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)

@app.route("/user")
def user():
    pass


# 定義對象
class Role(db.Model):
    # 類變量定義了數據庫中的表名。如果沒有指定,會已類的名稱小寫為表名,也就是role
    __tablename__ = "roles"
    id = db.Column(db.Integer,primary_key=True)  # create table roles(id int(64) primary key, name varchar(64) unique);
    name = db.Column(db.String(64),unique=True)  # desc roles; def __repr__(self):
        return "<Role %s>" % self.name


class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True,index=True)
    def __repr__(self):
        return "<User %s>" % self.username

if __name__ == '__main__':
    app.run()

 

   外鍵和關聯的創建

# 定義對象
class Role(db.Model):
    # 類變量定義了數據庫中的表名。如果沒有指定,會已類的名稱小寫為表名,也就是role
    __tablename__ = "roles"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64),unique=True)
    us = db.relationship("User",backref="role")  # us這個字段,關聯了User類(要寫類名):backref="role"表明User類中可以反向引用role對象。 def __repr__(self):
        return "<Role %s>" % self.name


class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True,index=True)
    role_id = db.Column(db.Integer,db.ForeignKey("roles.id"))  # role_id 是關聯了roles表的id字段。 def __repr__(self):
        return "<User %s>" % self.username

# 一對多的關系:一個role可以對應多個user用戶。

 

  插入數據:

  報錯:'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app) # 錯誤一:db在app.config之后設置,應該為之前設置。
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest" # 錯誤二:SQLALCHEMY_DATABASE_URI不是URL
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = False   #SQLALCHEMY_COMMIT_ON_TEARDOWN 鍵,將其設為True時,每次請求結束后都會自動提交數據庫中的變動
app.config['SQLALCHEMY_ECHO'] = True

 

 

if __name__ == '__main__':
    app.run(debug=True)
    db.create_all()  # 執行所有的類,進行建表。roles 和 user表創建成功。
    r1 = Role(name="admin") # 給roles表中插入數據
    db.session.add(r1)
    db.session.commit()




 

   刪除所有的表

app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 將這個從False改為True,請求后數據庫自動提交數據變動,要不然刪除不成功

if __name__ == '__main__':
  app.run(debug=True)
  db.drop_all() # 刪除所有的表
  db.session.commit() 

 

 再次創建所有表

if __name__ == '__main__':
    app.run(debug=True)
    db.create_all()
    db.session.commit()

 

 再次執行刪除所有的表

if __name__ == '__main__':
    app.run(debug=True)
    db.drop_all()
    db.session.commit()

但是結果:表依然沒有刪除掉

到底是什么原因呢?

解決辦法:重新啟動flask框架,后再次執行后,才能實現刪除表。

 

注意:重新建表和插入數據,也得重啟flask框架才能生效。

if __name__ == '__main__':
    app.run(debug=True)
    db.create_all()
    r1 = Role("admin")
    r2 = Role("no_admin")
    db.session.add_all([r1, r2])
    db.session.commit()
問題:只執行了創表語句,插入語句沒有執行,什么原因?是不是因為要db.create_all()也要用db.session.commit()

if __name__ == '__main__':
    app.run(debug=True)
    db.create_all()
    db.session.commit()
    r1 = Role(name="admin")
    r2 = Role(name="noadmin")
    db.session.add_all(r1,r2)
    db.session.commit()
更改后:依然只能執行建表語句,插入數據不成功,到底是什么原因呢?原因是列表 db.session.add_all([r1,r2])沒有加列表。然后還是要重啟,框架插入語句才能被查詢到。

全部的問題:框架運行到app.run()就阻塞了,當關閉框架時,會執行到,后面的語句,語句才生效,我太笨了。

繼續連續兩次ctrl+s框架自動刷新,報錯:

sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1062, "Duplicate entry 'aaaaaa' for key 'name'") [SQL: 'INSERT INTO title (name) VALUES (%(name)s)'] [parameters: {'name': 'aaaaaa'}]
原因是:username設置的 unique=True,再次插入遇到重復的名字就報錯了。

三:sqlalchemy語句的操作

實例:通過python shell 的方式操作數據庫

  終端中打開 ipython

  輸入 from mysql_tesst impoty User,Role 報錯:

  Non-ASCII character '\xe7' in file mysql_test.py on line 16, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details。

  原因是:ipython 版本默認使用的是 Python2.7.12 在python2的版本中,程序中有中文或者中文注釋,第一行必須加上,# encoding: utf-8。

  pip3 install ipython 將ipython的版本換成python3的版本就行了

 

 下面將使用python shell的ipython3操作數據庫

  1.表中插入數據

from mysql_test import User,db

r1 = Role(name="Admin2")  # 1.模型定義:

print(r1.id)  # None

db.session.add(r1) # 2.增加模型到數據庫的操作層

db.session.commit() # 3.將模型轉換為mysql的原生語句,進行插入數據。

print(r1.id) # 3  # 獲取表中某個字段,直接通過實例屬性r1.id進行取值,方便 select id from roles where name="Admin2" 



# 為什么id不是按照順序排列的,
# 原因是:id字段設置時候,只是設置了為primary key並沒有設置為自增類型,auto_increment

 

   2. 修改表中的字段信息

還是在上次的shell基礎上進行操作

要求:將表中的Admin2字典修改為admin2

r1.name = "admin2" # 通過賦值的方式修改表中name的值 
db.session.add(r1)  

db.session.commit()

print(r1.name)  # admin2


 

   3. 刪除表的數據

# 接着上面的shell

db.session.delete(r1)

db.session.commit()


 

   4.查詢數據:sqlalchemy提供了 query對象進行數據查詢

Role.query.all()  # query.all()表示查詢所有的數據

[<Role admin>, <Role noadmin>]  查詢操作,沒有修改表的結構,因此不需要session.commit():返回的是查詢的對象

返回的樣式為什么是這樣呢?
def __repr__(self):
return "<Role %s>" % self.username

原因是:模型類中定義的這個函數進行決定的。

 

   查詢數據query配合過濾器filter可以更加准確的查詢所需要的數據

User.query.filter_by(username="張惠妹").all()  

[<User 張惠妹>]  # 顯示的樣式同上

 
        

 

   查詢users中用戶id大於2的所有用戶

User.query.filter_by(id>1).all()  # 原因filter_by只能用於等值過濾
User.query.filter(id>1).all() # 原因:id 應該改為User.id 表示是這個表的id字段。

# 以上兩種方式的查詢均報錯:
unorderable types: builtin_function_or_method() > int() 

擴展:filter()中條件的寫法

  users = User.query.filter(條件1).first()
  條件的寫法:
  User.name.endswith('g')
  User.name.startswith('g')
  User.name.containswith('g')
  User.name == “laowang”
  User.age == 12
  User.age > 12
  User.id.in_(列表)

 

   查詢users中的id大於2且名字為張學良的用戶

User.query.filter(User.id>1 ,User.username=="張學良").all() 

[<User 張學良>]

擴展:filter()中多條件查詢的寫法

  users = User.query.filter(條件1,條件2,條件3).first()
  users = User.query.filter(or_(條件1,條件2,條件3)).first()
  users = User.query.filter(not_(條件1)).all()

 

   其他的過濾條件

排序 
    User.query.order_by(字段.哪一種排序).all()
    User.query.order_by(User.name.desc()).all()


分頁
    aa = User.query.paginate(第幾頁,每一頁幾條)
    aa.pages
    aa.page
    aa.items

  執行函數

 

3.視圖中操作數據庫

  # todo

  

 


免責聲明!

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



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