国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SqlAlchemy使用教程(六) -- ORM 表間關(guān)系的定義與CRUD操作

這篇具有很好參考價(jià)值的文章主要介紹了SqlAlchemy使用教程(六) -- ORM 表間關(guān)系的定義與CRUD操作。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

SqlAlchemy使用教程(六) -- ORM 表間關(guān)系的定義與CRUD操作,數(shù)據(jù)庫(kù),python,flask,scrapy,pandas,pytorch

  • SqlAlchemy使用教程(一) 原理與環(huán)境搭建
  • SqlAlchemy使用教程(二) 入門(mén)示例及編程步驟
  • SqlAlchemy使用教程(三) CoreAPI訪問(wèn)與操作數(shù)據(jù)庫(kù)詳解
  • SqlAlchemy使用教程(四) MetaData 與 SQL Express Language 的使用
  • SqlAlchemy使用教程(五) ORM API 編程入門(mén)

本章內(nèi)容,稍微有些復(fù)雜,建議騰出2小時(shí)空閑時(shí)間,沖杯咖啡或泡杯茶 ?? , 慢慢看,在電腦上跑下代碼,可以加深理解.

六、表間關(guān)系的定義與CRUD操作

表間關(guān)系主要包括:一對(duì)多,一對(duì)一,多對(duì)多。其中一對(duì)多關(guān)系中也隱含了多對(duì)一關(guān)系。
表間關(guān)系是數(shù)據(jù)庫(kù)操作中的重要技術(shù)點(diǎn),非常有必要理解與掌握。

1、 一對(duì)多表間關(guān)系的定義

一對(duì)多表間關(guān)系實(shí)現(xiàn)語(yǔ)法

以一對(duì)多關(guān)系為例,

  • 子表側(cè),與父表是一對(duì)多關(guān)系,
  • 父表側(cè),可以反向查詢(xún)子表數(shù)據(jù),與子表是多對(duì)一關(guān)系。
class Parent(Base):
    __tablename__ = "parent_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    children: Mapped[List["Child"]] = relationship(back_populates="parent")


class Child(Base):
    __tablename__ = "child_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    parent_id: Mapped[int] = mapped_column(ForeignKey("parent_table.id"))
    parent: Mapped["Parent"] = relationship(back_populates="children")

說(shuō)明:
1)在子表中添加外鍵字段,以及relationship()引用,
2)在父表中添加relationship()引用,用于反向查詢(xún)。

示例代碼

父表:company, 子表 person, 表結(jié)構(gòu)類(lèi)定義如下。

from sqlalchemy.orm import DeclarativeBase, Session
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy import ForeignKey
from sqlalchemy import String, Integer
from typing import List

class Base(DeclarativeBase):
    pass
class Company(Base):
    __tablename__ = "company"
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    company_name: Mapped[str] = mapped_column(String(30), index=True)
    persons: Mapped[List['Person']] = relationship(
        back_populates="company", cascade="all, delete-orphan")

    def __repr__(self) -> str:
        return f"Company(id={self.id}, company_name={self.company_name})"

class Person(Base):
    __tablename__ = "person"
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    name: Mapped[str] = mapped_column(String(30))
    age: Mapped[int] = mapped_column(Integer)
    company_id: Mapped[int] = mapped_column(ForeignKey("company.id"))
    company: Mapped['Company'] = relationship(back_populates="persons")

    def __repr__(self) -> str:
        return f"Person(id={self.id}, name={self.name})"

說(shuō)明:
1)從子表視角看,1個(gè)人只屬于1個(gè)Company; 但1個(gè)Company 對(duì)應(yīng)多個(gè)人,因此在父表則,relationship() 左側(cè)的類(lèi)型注解為 List[‘Person’], 也可以用Set[‘Person’]
2)父表中添加刪除依賴(lài),cascade=“all, delete-orphan”,即子表中不存在對(duì)父表記錄的引用時(shí),才能刪除,以保證數(shù)據(jù)的完整性。
3)當(dāng)前版本可能存在bug, 官方文檔中的示例中有的字段使用簡(jiǎn)化寫(xiě)法(右側(cè)未給出mapped_column()),sqlite3運(yùn)行是沒(méi)有問(wèn)題的,但mysql, postgresql創(chuàng)建表時(shí)會(huì)丟棄簡(jiǎn)化寫(xiě)法的字段,導(dǎo)致后續(xù)insert等操作失敗。 因此請(qǐng)嚴(yán)格請(qǐng)勿采有簡(jiǎn)化寫(xiě)法。

多對(duì)一關(guān)系的實(shí)現(xiàn)語(yǔ)法

當(dāng)不需要反向查詢(xún)時(shí),則父表與子表形成Many to One 多對(duì)一關(guān)系, 在父表則添加子表的外鍵與relationship()引用,子表無(wú)須做額外配置

class Parent(Base):
    __tablename__ = "parent_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    child_id: Mapped[int] = mapped_column(ForeignKey("child_table.id"))
    child: Mapped["Child"] = relationship()


class Child(Base):
    __tablename__ = "child_table"
    id: Mapped[int] = mapped_column(primary_key=True)

如果允許 child_id空值,則將改字段的類(lèi)型注解修改為

from typing import Optional
......
child_id: Mapped[Optional[int]] = mapped_column(ForeignKey("child_table.id"))

對(duì)于3.10+版本,類(lèi)型注解支持 | 操作符

child_id: Mapped[int | None] = mapped_column(ForeignKey("child_table.id"))
child: Mapped[Child | None] = relationship(back_populates="parents")

2、 插入數(shù)據(jù)與多表聯(lián)合查詢(xún)

1)在數(shù)據(jù)庫(kù)創(chuàng)建表

# 創(chuàng)建數(shù)據(jù)庫(kù)連接引擎對(duì)象
engine = create_engine(
    "mysql+mysqlconnector://root:Admin&123@localhost:3306/testdb")
# 將DDL語(yǔ)句映射到數(shù)據(jù)庫(kù)表,如果數(shù)據(jù)庫(kù)表不存在,則創(chuàng)建該表
Base.metadata.create_all(engine)
# 打印創(chuàng)建創(chuàng)建的表
Print(Base.metadata.tables) 

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

基本步驟包括:

(1)為測(cè)試方便,先寫(xiě)1個(gè)get_or_create()函數(shù),如果插入對(duì)象在數(shù)據(jù)庫(kù)中已存在則不插入,以方便連續(xù)測(cè)試。
(2)創(chuàng)建session對(duì)象
(3)先創(chuàng)建父表對(duì)象并插入
(4)創(chuàng)建子表對(duì)象并插入
(5)用多表查詢(xún)方法檢查結(jié)果

Step-1: 自定義create_or_create()函數(shù)

官方提供的upsert方法不通用。下面函數(shù)是通用的,

def get_or_create(session, model, defaults=None, **kwargs):
    """如果不存在則創(chuàng)建,如果存在則返回
    輸入?yún)?shù):
        session: sqlalchemy session
        model: 自定義的ORM類(lèi)
        defaults: 有默認(rèn)值的字段
        kwargs: 其他字段(必須包含主要字段)
    返回值:
        instance: 返回的實(shí)例
    """
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        print("instance already exists", instance)
        return instance
    else:
        params = dict((k, v) for k, v in kwargs.items()
                      if not isinstance(v, ClauseElement))
        if defaults:
            params.update(defaults)
        instance = model(**params)
        session.add(instance)
        session.commit()
        print("instance inserted", instance)
        return instance
Step-2: 向兩個(gè)關(guān)聯(lián)表插入數(shù)據(jù)

用with 語(yǔ)句創(chuàng)建session對(duì)象,插入操作順序,先父表再子表

with Session(engine) as session:
    # 插入數(shù)據(jù)
    get_or_create(session, Company, company_name="蜀漢")
    get_or_create(session, Company, company_name="曹魏")
    get_or_create(session, Company, company_name="東吳")
    
    stmt = select(Company)
    results = session.scalars(stmt)
    print(results.all())

    # insert data in person table
    company_shu = session.scalars(select(Company).where(
        Company.company_name == "蜀漢")).first()
    get_or_create(session, Person, name="劉備",
                  age=42, company=company_shu)
    get_or_create(session, Person, name="關(guān)羽",
                  age=40, company=company_shu)
    get_or_create(session, Person, name="張飛", age=38, company=company_shu)
    company_wei = session.scalars(select(Company).where(
        Company.company_name == "曹魏")).first()
    get_or_create(session, Person, name="張遼", age=40, company=company_wei)
    get_or_create(session, Person, name="曹操", age=38, company=company_wei)
    company_wu = session.scalars(select(Company).where(
        Company.company_name == "東吳")).first()
    get_or_create(session, Person, name="周瑜", age=30, company=company_wu)

3) 多表聯(lián)合查詢(xún)

   # select with Join 多表查詢(xún)
    stmt = select(Person).join(Person.company).where(
        Company.company_name == "蜀漢").order_by(Person.age)
    results = session.scalars(stmt)
    # 遍歷結(jié)果
    for r in results:
        print(r.name, r.age, r.company.company_name)

Output:

instance inserted Company(id=1, company_name=蜀漢)
instance inserted Company(id=2, company_name=曹魏)
instance inserted Company(id=3, company_name=東吳)
[Company(id=1, company_name=蜀漢), Company(id=2, company_name=曹魏), Company(id=3, company_name=東吳)]
instance inserted Person(id=1, name=劉備)
instance inserted Person(id=2, name=關(guān)羽)
instance inserted Person(id=3, name=張飛)
instance inserted Person(id=4, name=張遼)
instance inserted Person(id=5, name=曹操)
instance inserted Person(id=6, name=周瑜)
張飛 38 蜀漢
關(guān)羽 40 蜀漢
劉備 42 蜀漢

刪除數(shù)據(jù)
當(dāng)刪除父表記錄時(shí),子表中應(yīng)無(wú)對(duì)此數(shù)據(jù)的引用,否則無(wú)法刪除。

3、 一對(duì)一關(guān)系

從外鍵角度看,一對(duì)一關(guān)系也是一對(duì)多關(guān)系。實(shí)現(xiàn)時(shí),

  • 在父表中收集子表數(shù)據(jù)時(shí),類(lèi)型注解不使用集合類(lèi)型即可。
  • 子表中relationship()方法中添加single_parent=True.
class Parent(Base):
    __tablename__ = "parent_table"
    id: Mapped[int] = mapped_column(primary_key=True)
child: Mapped["Child"] = relationship(back_populates="parent")   
    # 一對(duì)多時(shí),使用child: Mapped[List["Child"]] 


class Child(Base):
    __tablename__ = "child_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    parent_id: Mapped[int] = mapped_column(ForeignKey("parent_table.id"))
    parent: Mapped["Parent"] = relationship(back_populates="child",single_parent=True)

4、 多對(duì)多關(guān)系

多對(duì)多關(guān)系特點(diǎn):
1)父表與子表,子表與父表之間均為多對(duì)多關(guān)系。
2)通常使用1張中間表, 與父表、子表均實(shí)現(xiàn)1對(duì)多關(guān)系。
(當(dāng)然有的ORM模型將中間表的創(chuàng)建隱藏起來(lái),但在數(shù)據(jù)庫(kù)中還是可以看到)

多對(duì)多關(guān)系定義示例

from __future__ import annotations

from sqlalchemy import Column
from sqlalchemy import Table
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import relationship


class Base(DeclarativeBase):
    pass


# note for a Core table, we use the sqlalchemy.Column construct,
# not sqlalchemy.orm.mapped_column
association_table = Table(
    "association_table",
    Base.metadata,
    Column("left_id", ForeignKey("left_table.id")),
    Column("right_id", ForeignKey("right_table.id")),
)


class Parent(Base):
    __tablename__ = "left_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    children: Mapped[List[Child]] = relationship(
        secondary=association_table, back_populates="parents"
    )


class Child(Base):
    __tablename__ = "right_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    parents: Mapped[List[Parent]] = relationship(
        secondary=association_table, back_populates="children"
    )

多對(duì)多關(guān)系的查詢(xún)、插入操作與一對(duì)多查詢(xún)相似。 需要注意的是刪除操作。

從多對(duì)多關(guān)系中刪除數(shù)據(jù)

用SQL來(lái)實(shí)現(xiàn)時(shí),需要先從父表與子表刪除數(shù)據(jù),再?gòu)闹虚g表刪除。ORM API 可以自動(dòng)完成這個(gè)過(guò)程。 如要?jiǎng)h除子表的某條記錄。

myparent.children.remove(somechild)

注:通過(guò)session.delete(somechild)時(shí),MySql可能會(huì)報(bào)錯(cuò),我遇到的原因有多種,不建議使用。
同樣,如果要?jiǎng)h除父表中的1條記錄:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-817512.html

mychild.parent.remove(someparent) 

到了這里,關(guān)于SqlAlchemy使用教程(六) -- ORM 表間關(guān)系的定義與CRUD操作的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • SqlAlchemy使用教程(三) CoreAPI訪問(wèn)與操作數(shù)據(jù)庫(kù)詳解

    SqlAlchemy使用教程(三) CoreAPI訪問(wèn)與操作數(shù)據(jù)庫(kù)詳解

    SqlAlchemy使用教程(一) 原理與環(huán)境搭建 SqlAlchemy使用教程(二) 入門(mén)示例及編程步驟 SqlAlchemy使用教程(三) CoreAPI訪問(wèn)與操作數(shù)據(jù)庫(kù)詳解 SqlAlchemy使用教程(四) MetaData 與 SQL Express Language 的使用 SqlAlchemy使用教程(五) ORM API 編程入門(mén) Sqlalchemy 的Core部分集成了DB API, 事務(wù)管理,schema描述等

    2024年02月02日
    瀏覽(19)
  • 3.flask-sqlalchemy ORM庫(kù)

    Flask-SQLAlchemy是一個(gè)用于Flask的擴(kuò)展,它提供了一個(gè)便捷的方式來(lái)處理數(shù)據(jù)庫(kù)操作。Flask-SQLAlchemy基于SQLAlchemy,一個(gè)功能強(qiáng)大的Python SQL工具包和對(duì)象關(guān)系映射(ORM)系統(tǒng) 官網(wǎng)文檔: http://www.pythondoc.com/flask-sqlalchemy/ 一對(duì)多關(guān)系是指一個(gè)模型與另一個(gè)模型之間存在多對(duì)一的關(guān)系。在

    2024年02月10日
    瀏覽(30)
  • Flask SQLAlchemy_Serializer ORM模型序列化

    Flask SQLAlchemy_Serializer ORM模型序列化

    在前后端分離項(xiàng)目中,經(jīng)常需要把ORM模型轉(zhuǎn)化為字典,再將字典轉(zhuǎn)化為JSON格式的字符串。在遇到sqlalchemy_serializer之前,我都是通過(guò)類(lèi)似Java中的反射原理,獲取當(dāng)前ORM模型的所有字段,然后寫(xiě)一個(gè)to_dict方法來(lái)將字段以及他的值封裝成字典。大概的代碼如下所示: 這種做法雖然

    2024年02月16日
    瀏覽(17)
  • python常用庫(kù)之?dāng)?shù)據(jù)庫(kù)orm框架之SQLAlchemy

    python常用庫(kù)之?dāng)?shù)據(jù)庫(kù)orm框架之SQLAlchemy

    官網(wǎng):https://www.sqlalchemy.org/ SQLAlchemy是一個(gè)基于Python實(shí)現(xiàn)的SQL工具包和ORM框架,提供了高層抽象來(lái)管理數(shù)據(jù)庫(kù)交互。 SQLAlchemy功能強(qiáng)大,可以省去很多手動(dòng)管理數(shù)據(jù)庫(kù)連接、資源、事務(wù)等重復(fù)工作,讓開(kāi)發(fā)者更加高效地使用數(shù)據(jù)庫(kù)。許多大型Python項(xiàng)目都選擇使用SQLAlchemy作為ORM框架

    2024年02月07日
    瀏覽(51)
  • Django 4.2.7 ORM 連接MySQLServer 完成單表CRUD

    Django 4.2.7 ORM 連接MySQLServer 完成單表CRUD

    Django 模型使用自帶的 ORM。 對(duì)象關(guān)系映射(Object Relational Mapping,簡(jiǎn)稱(chēng) ORM )用于實(shí)現(xiàn)面向?qū)ο缶幊陶Z(yǔ)言里不同類(lèi)型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換。 ORM 在業(yè)務(wù)邏輯層和數(shù)據(jù)庫(kù)層之間充當(dāng)了橋梁的作用。 ORM 是通過(guò)使用描述對(duì)象和數(shù)據(jù)庫(kù)之間的映射的元數(shù)據(jù),將程序中的對(duì)象自動(dòng)持久化

    2024年02月02日
    瀏覽(30)
  • flask---》更多查詢(xún)方式/連表查詢(xún)/原生sql(django-orm如何執(zhí)行原生sql)/flask-sqlalchemy

    sqlalchemy執(zhí)行原生sql django執(zhí)行原生sql

    2024年02月13日
    瀏覽(23)
  • SqlAlchemy使用教程(一) 原理與環(huán)境搭建

    SqlAlchemy使用教程(一) 原理與環(huán)境搭建

    SqlAlchemy使用教程(一) 原理與環(huán)境搭建 SqlAlchemy使用教程(二) 入門(mén)示例及編程步驟 SqlAlchemy使用教程(三) CoreAPI訪問(wèn)與操作數(shù)據(jù)庫(kù)詳解 SqlAlchemy使用教程(四) MetaData 與 SQL Express Language 的使用 SqlAlchemy使用教程(五) ORM API 編程入門(mén) SqlAlchemy使用教程(六) – ORM 表間關(guān)系的定義與CRUD操作

    2024年01月16日
    瀏覽(30)
  • 什么是ORM(對(duì)象關(guān)系映射)?

    ORM(對(duì)象關(guān)系映射)是一種編程技術(shù),用于在關(guān)系型數(shù)據(jù)庫(kù)和面向?qū)ο缶幊陶Z(yǔ)言之間建立映射關(guān)系。它的目標(biāo)是通過(guò)自動(dòng)化和簡(jiǎn)化數(shù)據(jù)訪問(wèn)層的開(kāi)發(fā),將數(shù)據(jù)庫(kù)表和記錄映射到面向?qū)ο缶幊陶Z(yǔ)言中的對(duì)象和類(lèi)。 ORM提供了一種將數(shù)據(jù)庫(kù)中的數(shù)據(jù)轉(zhuǎn)換為編程語(yǔ)言中的對(duì)象的機(jī)制,

    2024年02月12日
    瀏覽(71)
  • 軟件測(cè)試|sqlalchemy一對(duì)一關(guān)系詳解

    軟件測(cè)試|sqlalchemy一對(duì)一關(guān)系詳解

    簡(jiǎn)介 SQLAlchemy 是一個(gè)強(qiáng)大的 Python ORM(對(duì)象關(guān)系映射)庫(kù),它允許我們將數(shù)據(jù)庫(kù)表映射到 Python 對(duì)象,并提供了豐富的關(guān)系模型來(lái)處理不同類(lèi)型的關(guān)系,包括一對(duì)一關(guān)系。在本文中,我們將深入探討 SQLAlchemy 中表一對(duì)一關(guān)系的概念,以及如何在模型中定義和使用這種關(guān)系。 什

    2024年01月17日
    瀏覽(22)
  • 四、使用Kibana執(zhí)行elasticsearch的CRUD操作

    四、使用Kibana執(zhí)行elasticsearch的CRUD操作

    目錄 使用kibana測(cè)試 1、創(chuàng)建一個(gè)索引 2、創(chuàng)建索引并添加數(shù)據(jù) 3、獲取索引的具體信息 4、通過(guò)GET請(qǐng)求_cat查看所有的_cat命令 5、修改數(shù)據(jù) 5.1、使用PUT修改 5.2、使用POST最后加上_update修改 6、刪除文檔 7、刪除索引 8、查詢(xún)操作 Rest風(fēng)格說(shuō)明 ????????Rest是一種軟件架構(gòu)風(fēng)格,而

    2024年02月09日
    瀏覽(13)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包