ORM模型進階

Flask SQLAlchemy管理數(shù)據(jù)庫

關(guān)系型數(shù)據(jù)庫框架覆旭,支持多種數(shù)據(jù)庫西壮,提供高層ORM, 也支持執(zhí)行原生SQL

$ pip install flask-sqlalchemy
$ pip install pymysql

數(shù)據(jù)庫連接URL

Mysql

mysql+pymysql://username:password@server/db

創(chuàng)建數(shù)據(jù)庫 mysql控制臺
mysql> create database school4 default character set = utf8;

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 設(shè)置數(shù)據(jù)庫連接字符串
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:Vff123456@127.0.0.1/school4?charset=UTF8MB4'
# 不跟蹤修改,不設(shè)置會有警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 創(chuàng)建數(shù)據(jù)庫連接
db = SQLAlchemy(app)

import application.models
import application.views

manager = Manager(app)

定義模型

from application import db
import datetime

# 用戶表
class Users(db.Model):
    __tablename__ = 'users'
    # 主鍵
    id = db.Column(db.Integer, primary_key=True)
    # 用戶名 唯一索引
    username = db.Column(db.String(128), unique=True, nullable=False)
    # 密碼 必填字段
    password = db.Column(db.String(512), nullable=False)
    # 姓名 創(chuàng)建索引讯嫂,加快查詢
    fullname = db.Column(db.String(128), index=True, nullable=False)
    # 狀態(tài) (1: 生效 0: 禁用)
    status = db.Column(db.SmallInteger, default=1, nullable=False)
    # 創(chuàng)建時間 默認當前時間
    created_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow, index=True)

    def __repr__(self):
        return 'username=%s' % username    

根據(jù)model創(chuàng)建表

$ python manage.py shell
>>> from application import db
>>> db.drop_all()
>>> db.create_all()

插入數(shù)據(jù)

$ python manage.py shell
>>> user = Users(username='lisa', password='asdasdfad', fullname='李霞')
>>> db.session.add(user) # 添加到數(shù)據(jù)庫會話中
>>> db.session.commit() # 提交數(shù)據(jù)
>>> db.session.rollback() # 數(shù)據(jù)庫回滾會有效么?試下放在commit前面呢氯材?

查詢數(shù)據(jù)

>>> Users.query.all()  # 查詢?nèi)?>>> Users.query.filter_by(username='lisa') # 返回一個新查詢
>>> Users.query.filter_by(username='lisa').all() # 返回查詢結(jié)果
>>> Users.query.filter(Users.username=='lisa').first_or_404()
>>> str(Users.query.filter(Users.username=='lisa3')) # 查看sql語句
>>> db.session.execute('select * from users where id = 1').first() # 原生sql語句

修改行

user = Users.query.get(1)
user.password = '123412343'
db.session.add(user)
db.session.commit()

刪除行

db.session.delete(user)
db.session.commit()

關(guān)系

一對多關(guān)系

# 學生表
class Student(db.Model):
    __tablename__ = 'student'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True, nullable=False)
    # 建立指向班級的外鍵
    class_id = db.Column(db.Integer, db.ForeignKey('class.id'))

    def __repr__(self):
        return 'student=%s' % self.name  

# 班級表
class Class(db.Model):
    __tablename__ = 'class'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True, nullable=False)
    # 引用學生
    students = db.relationship('Student', backref='sclass')

一對多關(guān)系測試

>>> from application import db
>>> db.create_all()
>>> from application.models import *
>>> student1 = Student(name='lisa')
>>> db.session.add(student1)
>>> db.session.commit()
>>> c1 = Class(name='python1904')
>>> db.session.add(c1)
>>> db.session.commit()
>>> student1.sclass = c1

一對一關(guān)系

一對一關(guān)系可以用前面介紹的一對多關(guān)系 表示,但調(diào)用db.relationship() 時要把uselist設(shè)為False

student = db.relationship('Student', backref='sclass', uselist=False)

多對多關(guān)系建模

class StudentLesson(db.Model):
    __tablename__ = 'student_lesson'
    student_id = db.Column(db.Integer, db.ForeignKey('student.id'), primary_key=True)
    lesson_id = db.Column(db.Integer, db.ForeignKey('lesson.id'), primary_key=True)
    score = db.Column(db.Integer, nullable=True)

class Student(db.Model):
    __tablename__ = 'student'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True, nullable=False)
    lessons = db.relationship('StudentLesson', foreign_keys=[StudentLesson.student_id], backref=db.backref('student', lazy='joined'), lazy='dynamic', cascade='all, delete-orphan') `

    def __repr__(self):
        return 'student=%s' % self.name    

class Lesson(db.Model):
    __tablename__ = 'lesson'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True, nullable=False)
    students = db.relationship('StudentLesson', foreign_keys=[StudentLesson.lesson_id], backref=db.backref('lesson', lazy='joined'), lazy='dynamic', cascade='all, delete-orphan')

    def __repr__(self):
        return 'lesson=%s' % self.name    

多對多關(guān)系測試

>>> from application.models import *
>>> from application import db
>>> db.create_all()
>>> student1 = Student(name='carmack')
>>> student2 = Student(name='lisa')
>>> db.session.add_all([student1, student2])
>>> db.session.commit()
>>> lesson1 = Lesson(name='數(shù)學')
>>> lesson2 = Lesson(name='語文')
>>> db.session.add_all([lesson1, lesson2])
>>> db.session.commit()
>>> student_lesson = StudentLesson(student=student1, lesson=lesson1)
>>> db.session.add(student_lesson)
>>> db.session.commit()

常用的SQLAlchemy關(guān)系選項

  • backref
    在關(guān)系的另一個模型中添加反向引用
  • primaryjoin
    明確指定兩個模型之間使用的聯(lián)結(jié)條件硝岗。只在模棱兩可的關(guān)系中需要指定
  • lazy
    指定如何加載相關(guān)記錄氢哮。可選值有 select(首次訪問時按需加載)型檀、immediate(源對象加 載后就加載)冗尤、joined(加載記錄,但使用聯(lián)結(jié))胀溺、subquery(立即加載裂七,但使用子查詢), noload(永不加載)和 dynamic(不加載記錄仓坞,但提供加載記錄的查詢)
  • uselist
    設(shè)為False背零,不使用列表

使用Flask-Migrate實現(xiàn)數(shù)據(jù)庫遷移

安裝migrate

pip install flask-migrate

配置使用migrate

初始化,使用app和db進行migrate對象的初始化

from flask_migrate import Migrate

#綁定app和數(shù)據(jù)庫
migrate = Migrate(app, db)

在Manager()對象上添加遷移指令

from flask_migrate import Migrate, MigrateCommand

app = Flask(__name__)

manage = Manager(app=app)

manage.add_command(‘db’, MigrateCommand)

操作:

python manage.py db init 初始化出migrations的文件无埃,只調(diào)用一次

python manage.py db migrate -m ‘comment’ 生成遷移文件

python manage.py db upgrade 執(zhí)行遷移文件中的升級

python manage.py db downgrade 執(zhí)行遷移文件中的降級

python manage.py db —help 幫助文檔

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末徙瓶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嫉称,更是在濱河造成了極大的恐慌侦镇,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件织阅,死亡現(xiàn)場離奇詭異壳繁,居然都是意外死亡,警方通過查閱死者的電腦和手機蒲稳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門氮趋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人江耀,你說我怎么就攤上這事剩胁。” “怎么了祥国?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵昵观,是天一觀的道長。 經(jīng)常有香客問我舌稀,道長啊犬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任壁查,我火速辦了婚禮觉至,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睡腿。我一直安慰自己语御,他們只是感情好峻贮,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著应闯,像睡著了一般纤控。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碉纺,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天船万,我揣著相機與錄音,去河邊找鬼骨田。 笑死耿导,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的盛撑。 我是一名探鬼主播碎节,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抵卫!你這毒婦竟也來了狮荔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤介粘,失蹤者是張志新(化名)和其女友劉穎殖氏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姻采,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡雅采,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了慨亲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婚瓜。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刑棵,靈堂內(nèi)的尸體忽然破棺而出巴刻,到底是詐尸還是另有隱情,我是刑警寧澤蛉签,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布胡陪,位于F島的核電站,受9級特大地震影響碍舍,放射性物質(zhì)發(fā)生泄漏柠座。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一片橡、第九天 我趴在偏房一處隱蔽的房頂上張望妈经。 院中可真熱鬧,春花似錦、人聲如沸狂塘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荞胡。三九已至,卻和暖如春了嚎,著一層夾襖步出監(jiān)牢的瞬間泪漂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工歪泳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萝勤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓呐伞,卻偏偏與公主長得像敌卓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伶氢,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容