最近看項目,又是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)