Flask-SQLAlchemy 與 SQL Alchemy 的區別、聯系


最近看項目,又是sqlalchemy,又有flask_sqlalchemy,兩者的一些用法差點搞混了。這里總結一下。


一、SQL Alchemy

SQL Alchemy是python中最著名的ORM(Object Relationship Mapping)框架。ORM:對象關系映射。即將用戶定義的Python類與數據庫表相關聯,並將這些類(對象)的實例與其對應表中的行相關聯。


1. SQL Alchemy 基本操作

1.1 連接數據庫

from sqlalchemy import create_engine

# 創建數據庫引擎
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/my_db?charset=utf8mb4")

create_engine()函數中的字符串的意義是,數據庫+數據庫連接框架://用戶名:密碼@IP地址:端口號/數據庫名稱?連接參數。

解釋:

連接mysql數據庫,采用的pymysql框架連接(當然還有其他的連接框架),登陸數據庫的用戶和密碼是root和123456,mysql數據庫系統地址時127.0.0.1:3306,連接的具體數據庫是my_db,並設置了字符編碼是utf8mb4。

1.2 聲明映射(建立數據庫表的模型)

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

# 聲明性基類
Base = declarative_base()

# 構建數據庫表的模型類
class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)

    # 這個是可選的方法,這里自定義在顯示User對象時的格式
    def __repr__(self):
        return "<User(name='%s', fullname='%s', nickname='%s')>" % (
                             self.name, self.fullname, self.nickname)

解釋:

使用Declarative系統映射的類是根據基類定義的,該基類維護相對於該基類的類和表的目錄 - 這稱為聲明性基類。我們的應用程序通常在一個常用的模塊中只有一個這個基礎的實例。我們使用declarative_base() 函數創建基類。

__tablename__變量聲明了在根據這個類創建表時表的名字。

現在我們有了一個類“Base”,我們可以根據它定義任意數量的映射類。上面我們根據它定義了一個users表,表中含有字段id、name、fullname

1.3 創建映射類的實例


user1 = User(name='ed', fullname='Ed Jones')
user2 = User(name='ed2', fullname='Ed2 Jones2')

1.4 創建會話

上面我們創建了連接數據庫的引擎,這里需要引擎來創建一個session,后面才能通過session與數據庫進行交互。


Session = sessionmaker(engine)
db_session = Session()

1.5 單表的增刪改查

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from Model import User

# 通常我們把數據庫表模型統一放到一個模塊里,所以這里需要導入

# 准備工作
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/SQLAlchemy_Pro?charset=utf8mb4")

Session = sessionmaker(engine)
db_session = Session()

# 1. 增加數據add(創建表結構的類名(字段名=添加的數據))
db_session.add(User(name="ZWQ", fullname="ZWQ zzzzz"))  # 相當於建立一條添加數據的sql語句
db_session.commit()  # 執行

# 批量添加
user1 = User(name='ed', fullname='Ed Jones')
user2 = User(name='ed2', fullname='Ed2 Jones2')
db_session.add_all([user1, user2])
db_session.commit()


# 2.查詢 query(表結構的類名)
res = db_session.query(User)
print(res)  # 直接翻譯輸出對應的SQL查詢語句

res = db_session.query(User).all()  # 返回表中所有數據對象
print(res)


for u in res:
    print(u.id, u.name, u.fullname)

res = db_session.query(Users).first()  # 取第一個,返回是對象
print(res.id, res.name)

res = db_session.query(User).filter(Users.id == 3).first()  # 返回符合條件查詢結果
print(res.name)

res = db_session.query(User).filter(User.id <= 2, User.name == "ZWQ").all() # filter中的條件可以是模糊條件,多個條件
for u in res:
    print(u.id,u.name)

# 3.更改數據 update({k:v})
res = db_session.query(Users).filter(Users.id == 1).update({"name":"DragonFire"})
print(res)
db_session.commit()

res = db_session.query(User).update({"name":"ZWQ"})  # 全部修改,返回修改的數據個數
print(res)
db_session.commit()

# 4.刪除 delete()結合查詢條件刪除
res = db_session.query(User).filter(User.id == 1).delete()  # 刪除否合條件的數據,返回刪除數量
print(res)
db_session.commit()

res = db_session.query(User).delete()  # 刪除表中所有數據,返回刪除數量
print(res)
db_session.commit()

# 關閉session
db_session.close()

回滾:如果我們通過db_session.add()不小心把錯誤的信息添加進去了,可以使用de_session.rollback()回滾操作。

2. SQL Alchemy之(一對多)(多對多)

參考文章:

https://blog.csdn.net/tianpingxian/article/details/82720442

看見了一片不錯的文章,就不自己寫了。當個參考好了。這篇文章有一對多,多對一,單向多對多(我有點懵),雙向多對多,以及他們的查詢等等,很詳細。


二、Flask-SQLAlchemy

Flask-SQLAlchemy 是一個為您的 Flask 應用增加 SQLAlchemy 支持的擴展。它需要 SQLAlchemy 0.6 或者更高的版本。它致力於簡化在 Flask 中 SQLAlchemy 的使用,提供了有用的默認值和額外的助手來更簡單地完成常見任務。


1. Flask-SQLAlchemy基本操作

1.1 一個簡單的示例:


from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# 實例化SQLAlchemy
db = SQLAlchemy()
# PS : 實例化SQLAlchemy的代碼必須要在引入藍圖之前

app = Flask(__name__)

# 配置數據庫連接
app.config[”SQLALCHEMY_DATABASE_URI“] = “mysql+pymysql://root:123456@127.0.0.1:3306/SQLAlchemy_Pro?charset=utf8mb4”

# 初始化SQLAlchemy , 本質就是將以上的配置讀取出來
db.init_app(app)

# 一個簡單的模型
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

# 根據模型在數據庫中生成相應的表
db.create_all()

1.2 簡單的增刪改查

# 導入模型
from your_application import User


# 創建數據
admin = User('admin', 'admin@example.com')
guest = User('guest', 'guest@example.com')


# 寫入到數據庫表中
db.session.add(admin)
db.session.add(guest)
db.session.commit()

# 查詢
users = User.query.all()
# [<User u'admin'>, <User u'guest'>]

admin = User.query.filter_by(username='admin').first()
# <User u'admin'>

2. Flask-SQLAlchemy的(一對多)(多對多)

2.1 一對多(one-to-many)關系


class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref='person',
                                lazy='dynamic')

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

**db.relationship() ** 這個函數返回一個可以做許多事情的新屬性。在本案例中,我們讓它指向 Address 類並加載多個地址。它如何知道會返回不止一個地址?因為 SQLALchemy 從您的聲明中猜測了一個有用的默認值。 如果您想要一對一關系,您可以把 uselist=False 傳給 relationship() 。

backref 是一個在 Address 類上聲明新屬性的簡單方法。您也可以使用 my_address.person 來獲取使用該地址(address)的人(person)。lazy 決定了 SQLAlchemy 什么時候從數據庫中加載數據它的值有:

  • 'select' :(默認值) 就是說 SQLAlchemy 會使用一個標准的 select 語句必要時一次加載數據。
  • 'joined' :告訴 SQLAlchemy 使用 JOIN 語句作為父級在同一查詢中來加載關系。
  • 'subquery' :類似 'joined' ,但是 SQLAlchemy 會使用子查詢。
  • 'dynamic' :不直接加載這些數據,SQLAlchemy 會返回一個查詢對象,在加載數據前您可以過濾(提取)它們。

詳細用法參見:(Flask - SQLalchemy 之 lazy 屬性)[https://www.jianshu.com/p/8427da16729a]

為反向引用(backrefs)定義惰性(lazy)狀態:使用 backref() 函數:


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref=db.backref('person', lazy='joined'), lazy='dynamic')

2.2 多對多(many-to-many)關系

如果想要用多對多關系,需要定義一個用於關系的輔助表。對於這個輔助表, 強烈建議不使用模型,而是采用一個實際的表:


# 輔助表
post_tag = db.Table('post_tag',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
)

# 文章模型
class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable = False)
    # 假如拿到了一個標簽Tag,怎么拿到標簽下的所有文章呢.反向引用Article這時用backref
    tags = db.relationship('Tag', secondary=post_tag, backref=db.backref('posts', lazy='dynamic'))

# 標簽模型
class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable = False)

其他操作:


article1 = Post(title = 'aaa')
article2 = Article(title = 'bbb')
tag1 = Tag(name = '111')
tag2 = Tag(name = '222')

#實現多對多關系,一個post有兩個標簽
article1.tags.append(tag1)
article1.tags.append(tag2)
article2.tags.append(tag1)
article2.tags.append(tag2)

# 增加
db.session.add(article1)
db.session.add(article2)
db.session.add(tag1)
db.session.add(tag2)

db.session.commit()

# 查詢
article1 = Post.query.filter(Post.title == 'aaa').first()

tags = article1.tags
for tag in tags:
    print(tag.name)


免責聲明!

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



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