欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

3個Python?SQLAlchemy數(shù)據(jù)庫操作功能詳解

 更新時間:2023年09月12日 10:37:07   作者:天行無忌  
Python?SQLAlchemy?是一個強大且多功能的?Python?SQL?工具包和對象關(guān)系映射?(ORM)?系統(tǒng),提供了一整套眾所周知的企業(yè)級持久性模式,本文為大家整理了它必須了解的3個數(shù)據(jù)庫操作功能,希望對大家有所幫助

Python 是一種多功能且富有表現(xiàn)力的編程語言,由于其簡單性和可讀性,已成為軟件開發(fā)的強大動力。本文學習 Python 數(shù)據(jù)庫的處理庫 SQLAlchemy。

Python SQLAlchemy 是一個強大且多功能的 Python SQL 工具包和對象關(guān)系映射 (ORM) 系統(tǒng),提供了一整套眾所周知的企業(yè)級持久性模式,專為高效和高性能的數(shù)據(jù)庫訪問而設計。它可以處理從小型簡單查詢到高負載場景中復雜事務的所有事務。它為開發(fā)人員提供了一個高級的 Pythonic 接口來與關(guān)系數(shù)據(jù)庫交互,允許使用 Python 類和對象來處理數(shù)據(jù)庫,而不是編寫復雜的 SQL 查詢,并以這種方式抽象代碼,刪除所有支持的數(shù)據(jù)庫腳本語句,例如 PostgreSQL、MySQL、SQLite 和 Oracle 等等。許多流行的 Python 框架都使用 SQLAlchemy,例如 Django、Flask 和 Pyramid。

本文一起來學習 SQLAlchemy 庫的三個有用功能,在大部分的項目開發(fā)中都可能用得上的功能。

下面先來了解一些基礎知識。

基礎知識

從這里開始介紹一些基本的知識,對于大多數(shù)人來說基本都是熟悉的知識。

數(shù)據(jù)模型

本文將以一個保存用戶記錄的簡單 SQL 表作為實例數(shù)據(jù),代碼將重點關(guān)注 SQLAlchemy 集成,以實現(xiàn)對數(shù)據(jù)存儲的需求,不涉及 Web 框架或任何其他復雜性。

為示例定義的基本用戶模型如下:

from pydantic import BaseModel
from typing import Optional
class UserSignUp(BaseModel):
    name: str
    surname: Optional[str] = None
    birth_year: Optional[int] = None
    notes: Optional[str] = None

在上面的代碼片段中,定義了一個 Pydantic 模型,它是想要在數(shù)據(jù)庫中保存記錄的數(shù)據(jù)的模型。Pydantic 是 Python 中最新且最有前途的庫,用于處理數(shù)據(jù)驗證、結(jié)構(gòu)和建模。如果不熟悉它,其實跟 Mongoose 、Prisma 實現(xiàn)原理相似。

存儲 Storage

出于存儲目的,將使用最簡單的 SQL 數(shù)據(jù)庫系統(tǒng)之一,即 SQLite。為此,需要定義一個引擎來與文件系統(tǒng)中實際的 SQLite 數(shù)據(jù)庫文件進行通信,并創(chuàng)建一個會話對象,以便可以與數(shù)據(jù)庫進行交互以進行操作。

from datetime import datetime
from pydantic import BaseModel
import os
import json
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base
from sqlalchemy.sql import func
from sqlalchemy import Column, DateTime, Integer, String
project_dir = os.path.dirname(os.path.abspath(__file__))
engine = create_engine("sqlite:///{}".format(os.path.join(project_dir, "./storage.db")),
                       connect_args={"check_same_thread": False})
Base = declarative_base()
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=True)
    surname = Column(String, nullable=True)
    birth_year = Column(Integer, nullable=True)
    notes = Column(String, nullable=True)
    register_date = Column(DateTime, default=func.now())
    def __repr__(self):
        dict_repr = {c.name: getattr(self, c.name) for c in self.__table__.columns}
        for key, value in dict_repr.items():
            if isinstance(value, datetime):
                dict_repr[key] = datetime.isoformat(value)
        return json.dumps(dict_repr, indent=2)
Base.metadata.create_all(bind=engine)

在上面的代碼片段中,項目文件夾路徑用于指向數(shù)據(jù)庫路徑。數(shù)據(jù)庫名稱定義為 storage.db,如果不存在,則會自動創(chuàng)建。

此外,使用 SQLAlchemy ORM 模塊的聲明函數(shù)來構(gòu)造一個基類,然后由 User 類來使用,User 類表示數(shù)據(jù)庫中保存用戶記錄的表。

表用戶行被定義為包含比我們?yōu)橛脩糇砸氲臄?shù)據(jù)模型額外的兩個字段。

User 表包含注冊引入的數(shù)據(jù)模型額外的兩個字段。

  • 一個自動增量整數(shù),作為已索引并用作表主鍵的行的 ID。
  • 注冊日期字段,它將當前時間戳作為默認參數(shù),這意味著正在數(shù)據(jù)庫中寫入的條目的時間戳。

數(shù)據(jù)庫表定義類還包含一個額外的魔術(shù)方法,__repr__ 方法在此處定義以實現(xiàn)自定義序列化器。這樣做的目的是可以直接打印數(shù)據(jù)庫記錄,即數(shù)據(jù)記錄行,因為它們是使用 SQLAlchemy 庫從表中獲取的。

最后,通過調(diào)用模塊 create_all 的方法,Base.metadata 在創(chuàng)建的數(shù)據(jù)庫中實例化定義的表結(jié)構(gòu)。因此,列及其數(shù)據(jù)類型和主鍵定義現(xiàn)在都存在。

寫入數(shù)據(jù)庫表

定義并創(chuàng)建了數(shù)據(jù)庫表,現(xiàn)在來嘗試寫入一條記錄。首先使用之前創(chuàng)建的引擎對象來創(chuàng)建一個到數(shù)據(jù)庫的會話。

from sqlalchemy import create_engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import sessionmaker
session_local = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db_session = session_local()

然后,使用聲明的數(shù)據(jù)模型創(chuàng)建一個要注冊的新用戶。

user_sign_up = UserSignUp(
    name="Quintion",
    surname="Tang",
    notes="一個工程師"
)

最后,使用 Users 的數(shù)據(jù)庫表類創(chuàng)建一個條目,以使用建立的會話寫入數(shù)據(jù)庫并提交更改。

try:
    user_to_store = User(
        name=user_sign_up.name,
        surname=user_sign_up.surname,
        birth_year=user_sign_up.birth_year,
        notes=user_sign_up.notes
    )
    db_session.add(user_to_store)
    db_session.commit()
    print(user_to_store)
except IntegrityError as e:
    db_session.rollback()
    print(f"用戶注冊時出錯:{str(e)}")

如果沒有因任何完整性錯誤引發(fā)異常,則應寫入該記錄并將其提交到數(shù)據(jù)庫。

{
  "id": 1,
  "name": "Quintion",
  "surname": "Tang",
  "birth_year": null,
  "notes": "一個工程師",
  "register_date": "2023-09-10T14:29:50"
}

請注意,birth_year 字段為空,因為首先沒有為其提供任何整數(shù),并且在寫入操作期間會自動為 register_date 生成時間戳。

數(shù)據(jù)驗證和預處理

在實際用例中,在存儲之前,首先都需要預先驗證或處理數(shù)據(jù)。

來看看將如何在這里做到這一點。例如,假設想要將每個字符串字段大寫。如果需要在數(shù)據(jù)庫中對數(shù)據(jù)進行標準化,這樣的過程將對于后期數(shù)據(jù)處理分析非常有用。統(tǒng)一字符串字段大寫的好處是在后續(xù)相關(guān)功能(如檢索)不必擔心區(qū)分大小寫的問題。

那么在 SQLAlchemy 中是如何使用其 ORM validates 裝飾器來完成此操作。

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=True)
    surname = Column(String, nullable=True)
    birth_year = Column(Integer, nullable=True)
    notes = Column(String, nullable=True)
    register_date = Column(DateTime, default=func.now())
    # 這里對數(shù)據(jù)進行預處理
    @validates('name', 'surname', 'notes')
    def normalize(self, _, value):
        if type(value) == str:
            return value.upper()
    def __repr__(self):
        dict_repr = {c.name: getattr(self, c.name) for c in self.__table__.columns}
        for key, value in dict_repr.items():
            if isinstance(value, datetime):
                dict_repr[key] = datetime.isoformat(value)
        return json.dumps(dict_repr, indent=2)

請注意,驗證裝飾器接受定義為字符串數(shù)據(jù)類型列的所有三列的參數(shù) @validates('name', 'surname', 'notes')。當然,這不是強制性的,可以使用任意數(shù)量的列并選擇不同的操作進行預處理。

函數(shù) normalize 將應用于所有選定的三列,傳入數(shù)據(jù)將通過此功能將要寫入數(shù)據(jù)庫的數(shù)據(jù)進行相應處理以返回所期望的大寫字符串。

再次運行的寫入操作現(xiàn)在將打印以下內(nèi)容:

{
  "id": 1,
  "name": "QUINTION",
  "surname": "TANG",
  "birth_year": null,
  "notes": "一個工程師",
  "register_date": "2023-09-10T15:29:50"
}

用于動態(tài)查詢數(shù)據(jù)的列屬性

在 Python SQLAlchemy 中,column_property 函數(shù)用于在 SQLAlchemy 類上創(chuàng)建計算屬性或別名屬性,這個屬性通常源自數(shù)據(jù)庫表中的一列或多列。column_property 函數(shù)允許在 SQLAlchemy 模型上定義其他屬性,這些屬性不直接映射到數(shù)據(jù)庫中的單個列,而是從現(xiàn)有列數(shù)據(jù)通過一定的計算或派生。

在上面用到的 User 數(shù)據(jù)表中,通常存儲的是具體的年月日,而要獲取用戶的年齡就需要經(jīng)過一定的計算。

from sqlalchemy import Column, DateTime, Integer, String
from sqlalchemy.sql import func, extract
from sqlalchemy.orm import column_property, validates
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=True)
    surname = Column(String, nullable=True)
    birth_year = Column(Integer, nullable=True)
    # 計算獲取年齡列數(shù)據(jù),此數(shù)據(jù)在數(shù)據(jù)庫中并非真實存在
    age = column_property(extract('year', func.now()) - birth_year)
    notes = Column(String, nullable=True)
    register_date = Column(DateTime, default=func.now())
    @validates('name', 'surname', 'notes')
    def normalize(self, _, value):
        if type(value) == str:
            return value.upper()
    def __repr__(self):
        dict_repr = {c.name: getattr(self, c.name) for c in self.__table__.columns}
        for key, value in dict_repr.items():
            if isinstance(value, datetime):
                dict_repr[key] = datetime.isoformat(value)
        dict_repr['age'] = self.age
        return json.dumps(dict_repr, indent=2)

上面代碼定義了新字段 age,它不是列類型,而是包含一個短表達式。使用來自 SQLAlchemy 的 sql 模塊的 extract 方法,由 func.now() 派生的時間戳中提取年份。以前見過這個,每當查詢表并動態(tài)派生時間戳時,該函數(shù)就會運行。通過提取當前時間戳的年份字段,減去用戶的出生年份,就可以計算出用戶的年齡。這個值不會存儲在數(shù)據(jù)表行中的任何位置,但會在查詢數(shù)據(jù)表的時候返回,是動態(tài)計算的。

由于字段 age 不是實際的列,因此它的值不會包含在 self.__table__.columns 字典中。當然還有其他的方法來達到這一目的。

下面來看看寫入數(shù)據(jù)庫和查詢數(shù)據(jù)的結(jié)果。

user_sign_up = UserSignUp(
    name="Quintion",
    surname="Tang",
    notes="一個工程師",
    birth_year=1988
)
try:
    user_to_store = User(
        name=user_sign_up.name,
        surname=user_sign_up.surname,
        birth_year=user_sign_up.birth_year,
        notes=user_sign_up.notes
    )
    db_session.add(user_to_store)
    db_session.commit()
    print(user_to_store)
except IntegrityError as e:
    db_session.rollback()
    print(f"用戶注冊時出錯:{str(e)}")

這次,提供出生年份,以便執(zhí)行年齡計算。

{
  "id": 1,
  "name": "QUINTION",
  "surname": "TANG",
  "birth_year": 1988,
  "notes": "一個工程師",
  "register_date": "2023-09-10T15:58:31",
  "age": 35
}

現(xiàn)在,字段 age 會動態(tài)填充并在每次查詢時返回。

主鍵之上多列的唯一約束

熟悉 SQL 數(shù)據(jù)庫系統(tǒng)的人從一開始就知道每個表都需要包含一個主鍵。主鍵是唯一標識表中每條記錄(行)的基本概念。它確保指定列中不存在重復值或空值,從而保證數(shù)據(jù)的完整性和唯一性。

然而,有時,需要對記錄條目進行更多限制。在某些場景中,主鍵并不能滿足所有需求。

舉一個例子,假設注冊用戶與現(xiàn)有數(shù)據(jù)表中的用戶具有完全相同的 namesurname ,在表主鍵只是一個增量數(shù)字的時候,是允許插入的。為了說明問題,驗證相同用戶名信息是否是同一個人,可以通過使用字段 name 、 surnamebirth_year 來標識兩個不同的記錄,也就是說,如果現(xiàn)有用戶的所有的這三個字段都相同,則應拒絕插入,這種規(guī)則稱為唯一性索引。

下面來看看如何在表中強制執(zhí)行這樣的規(guī)則:

import json
from sqlalchemy import UniqueConstraint
from sqlalchemy import Column, DateTime, Integer, String
from sqlalchemy.sql import func, extract
from sqlalchemy.orm import column_property, validates
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=True)
    surname = Column(String, nullable=True)
    birth_year = Column(Integer, nullable=True)
    age = column_property(extract('year', func.now()) - birth_year)
    notes = Column(String, nullable=True)
    register_date = Column(DateTime, default=func.now())
    # 增加多字段唯一性規(guī)則
    __table_args__ = (UniqueConstraint('name', 'surname', 'birth_year', name='unique_fullname_per_birth_year'),)
    @validates('name', 'surname', 'notes')
    def normalize(self, _, value):
        if type(value) == str:
            return value.upper()
    def __repr__(self):
        dict_repr = {c.name: getattr(self, c.name) for c in self.__table__.columns}
        for key, value in dict_repr.items():
            if isinstance(value, datetime):
                dict_repr[key] = datetime.isoformat(value)
        dict_repr['age'] = self.age
        return json.dumps(dict_repr, indent=2)

對象 UniqueConstraint 提供的表參數(shù),對象采用不同的列名作為參數(shù),這些列名稱形成每個記錄的唯一性,還可以為規(guī)則提供名稱。

這一特性就不再演示其效果了。下面是完整代碼:

from datetime import datetime
from pydantic import BaseModel
from typing import Optional
import os
import json
from sqlalchemy import create_engine, UniqueConstraint
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy import Column, DateTime, Integer, String
from sqlalchemy.sql import func, extract
from sqlalchemy.orm import column_property, validates
project_dir = os.path.dirname(os.path.abspath(__file__))
engine = create_engine("sqlite:///{}".format(os.path.join(project_dir, "./storage.db")),
                       connect_args={"check_same_thread": False})
Base = declarative_base()
class UserSignUp(BaseModel):
    name: str
    surname: Optional[str] = None
    birth_year: Optional[int] = None
    notes: Optional[str] = None
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=True)
    surname = Column(String, nullable=True)
    birth_year = Column(Integer, nullable=True)
    age = column_property(extract('year', func.now()) - birth_year)
    notes = Column(String, nullable=True)
    register_date = Column(DateTime, default=func.now())
    __table_args__ = (UniqueConstraint('name', 'surname', 'birth_year', name='unique_fullname_per_birth_year'),)
    @validates('name', 'surname', 'notes')
    def normalize(self, _, value):
        if type(value) == str:
            return value.upper()
    def __repr__(self):
        dict_repr = {c.name: getattr(self, c.name) for c in self.__table__.columns}
        for key, value in dict_repr.items():
            if isinstance(value, datetime):
                dict_repr[key] = datetime.isoformat(value)
        dict_repr['age'] = self.age
        return json.dumps(dict_repr, indent=2)
Base.metadata.create_all(bind=engine)
session_local = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db_session = session_local()
user_sign_up = UserSignUp(
    name="chris",
    surname="karvouniaris",
    notes="some notes about me",
    birth_year=1992
)
try:
    user_to_store = User(
        name=user_sign_up.name,
        surname=user_sign_up.surname,
        birth_year=user_sign_up.birth_year,
        notes=user_sign_up.notes
    )
    db_session.add(user_to_store)
    db_session.commit()
    print(user_to_store)
except IntegrityError as e:
    db_session.rollback()
    print(f"用戶注冊時出錯:{str(e)}")

總結(jié)

在處理任何規(guī)模的 Python 項目中的數(shù)據(jù)庫時,SQLAlchemy 是一個必須了解的工具,本文只是探索的一些非?;镜墓δ?,基本上也用得上。對于從事過后臺開發(fā)的朋友來說,這些都是很熟悉的。

以上就是3個Python SQLAlchemy數(shù)據(jù)庫操作功能詳解的詳細內(nèi)容,更多關(guān)于Python SQLAlchemy的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 淺談python 讀excel數(shù)值為浮點型的問題

    淺談python 讀excel數(shù)值為浮點型的問題

    今天小編就為大家分享一篇淺談python 讀excel數(shù)值為浮點型的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • python安裝完成后可以進行的后續(xù)步驟和注意事項小結(jié)

    python安裝完成后可以進行的后續(xù)步驟和注意事項小結(jié)

    本文詳細介紹了安裝Python3后的后續(xù)步驟,包括驗證安裝、配置環(huán)境、安裝包、創(chuàng)建和運行腳本,以及使用虛擬環(huán)境,還強調(diào)了注意事項,如系統(tǒng)更新、包管理與安全,感興趣的朋友一起看看吧
    2025-01-01
  • Pytorch mask_select 函數(shù)的用法詳解

    Pytorch mask_select 函數(shù)的用法詳解

    今天小編就為大家分享一篇Pytorch mask_select 函數(shù)的用法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • 使用SQLAlchemy操作數(shù)據(jù)庫表過程解析

    使用SQLAlchemy操作數(shù)據(jù)庫表過程解析

    這篇文章主要介紹了使用SQLAlchemy操作數(shù)據(jù)庫表過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • wxPython窗口的繼承機制實例分析

    wxPython窗口的繼承機制實例分析

    這篇文章主要介紹了wxPython窗口的繼承機制,較為詳細的講述了wxPython窗口的繼承機制及相關(guān)用法,并對其中的易錯點進行了簡單的分析,需要的朋友可以參考下
    2014-09-09
  • Python基礎之高級變量類型實例詳解

    Python基礎之高級變量類型實例詳解

    這篇文章主要介紹了Python基礎之高級變量類型,結(jié)合實例形式詳細分析了Python元組、字典、字符串、公共方法以及遍歷、切片等常見操作技巧,需要的朋友可以參考下
    2020-01-01
  • python小程序?qū)崿F(xiàn)刷票功能詳解

    python小程序?qū)崿F(xiàn)刷票功能詳解

    這篇文章主要介紹了python小程序?qū)崿F(xiàn)刷票功能詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-07-07
  • 使用實現(xiàn)XlsxWriter創(chuàng)建Excel文件并編輯

    使用實現(xiàn)XlsxWriter創(chuàng)建Excel文件并編輯

    今天小編就為大家分享一篇使用實現(xiàn)XlsxWriter創(chuàng)建Excel文件并編輯,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Django使用list對單個或者多個字段求values值實例

    Django使用list對單個或者多個字段求values值實例

    這篇文章主要介紹了Django使用list對單個或者多個字段求values值實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • python非遞歸全排列實現(xiàn)方法

    python非遞歸全排列實現(xiàn)方法

    下面小編就為大家?guī)硪黄猵ython非遞歸全排列實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04

最新評論