SQLALchemy backref章节文档

SQLAlchemy学习-5.relationship之backref和back_populates参数 relationship 函数是 sqlalchemy对关系之间提供的一种便利的调用方式, backref参数则对关系提供反向引用的声明。 在最新版本的sqlalchemy中对relationship引进了back_populates参数, 两个参数的效果完全一致。 阅读详情

Linking Relationships with Backref

自从在Object Relational Tutorial中第一次提到backref参数后,许多案例中也用到了backref,那么他到底做了什么?让我们从典型的”用户-地址”模型来探究吧.

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    addresses = relationship("Address", backref="user")

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(Integer, ForeignKey('user.id'))

上面的代码在User建立addresses属性,可以通过User.addresses查询对应的Address对象集合的.同样也在Address中建立了用于查询User对象的user属性.

实际上,backref关键字只是一个建立关系的快捷方式,他在Address中建立了关系映射,including the establishment of an event listener on both sides which will mirror attribute operations in both directions.上面的代码等价于:

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    addresses = relationship("Address", back_populates="user")

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(Integer, ForeignKey('user.id'))

    user = relationship("User", back_populates="addresses")

我们明确的在Address表中添加了.user关系,在两个关系中,back_populates明确的向另一边表明另一边需要在两表之间建立一个双向的联系.

这些代码主要做的是当append事件或者set事件发生时,把自己设置到对应对象的某个属性中.下面将用User-Address来简单阐明这一行为,address属性和user属性现在为空

>>> u1 = User()
>>> a1 = Address()
>>> u1.addresses
[]
>>> print a1.user
None

然而,当Address插入到u1.addresses中时,u1.addresses属性和a1.user属性同时被添加了内容

>>> u1.addresses.append(a1)
>>> u1.addresses
[<__main__.Address object at 0x12a6ed0>]
>>> a1.user
<__main__.User object at 0x12a6590>

反过来,设置a1.user时也一样,对两边的属性设置效果是等价.例如,当设置a1.user为None时,Address对象也同样从User的addresses中移除了.

>>> a1.user = None
>>> u1.addresses
[]

对.addresses属性和.user属性的操作完全是通过python完成的,而没有通过SQL交互环境操作,不然的话the proper state would be apparent on both sides once the data has been flushed to the database, and later reloaded after a commit or expiration operation occurs. backref/back_populates的优点是操作后不需要往返数据库就可以正确的反应出正确的状态

记住,backref关键字单独的用在一边和在关系两边使用back_populates关键字,效果是完全等价的


Backref Arguments

我们已经确定了backref关键字仅仅只是建立两个单独relationship()的快捷方式,设置在一个relationship()中的barkref配置将会自动设置在另一边.也就是说,两边的关系设置不太可能有差异. 一般情况,有secondary属性的多对多关系,或者是有primaryjoin属性的一对多,多对一关系(primaryjoin属性在Specifying Alternate Join Conditions中讨论过).Such as if we limited the list of Address objects to those which start with “tony”:

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)

addresses = relationship("Address",
                primaryjoin="and_(User.id==Address.user_id, "
                    "Address.email.startswith('tony'))",
                backref="user")

class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))

We can observe, by inspecting the resulting property, that both sides of the relationship have this join condition applied:

>>> print User.addresses.property.primaryjoin
"user".id = address.user_id AND address.email LIKE :email_1 || '%%'
>>>
>>> print Address.user.property.primaryjoin
"user".id = address.user_id AND address.email LIKE :email_1 || '%%'
>>>

This reuse of arguments should pretty much do the “right thing” - it uses only arguments that are applicable, and in the case of a many-to- many relationship, will reverse the usage of primaryjoin and secondaryjoin to correspond to the other direction (see the example in Self-Referential Many-to-Many Relationship for this).

It’s very often the case however that we’d like to specify arguments that are specific to just the side where we happened to place the “backref”. This includes relationship() arguments like lazy, remote_side, cascade and cascade_backrefs. For this case we use the backref() function in place of a string:

from sqlalchemy.orm import backref

class User(Base):
tablename = ‘user’
id = Column(Integer, primary_key=True)
name = Column(String)

addresses = relationship("Address",
                backref=backref("user", lazy="joined"))

Where above, we placed a lazy=”joined” directive only on the Address.user side, indicating that when a query against Address is made, a join to the User entity should be made automatically which will populate the .user attribute of each returned Address. The backref() function formatted the arguments we gave it into a form that is interpreted by the receiving relationship() as additional arguments to be applied to the new relationship it creates.

One Way Backrefs

An unusual case is that of the “one way backref”. This is where the “back-populating” behavior of the backref is only desirable in one direction. An example of this is a collection which contains a filtering primaryjoin condition. We’d like to append items to this collection as needed, and have them populate the “parent” object on the incoming object. However, we’d also like to have items that are not part of the collection, but still have the same “parent” association - these items should never be in the collection.

Taking our previous example, where we established a primaryjoin that limited the collection only to Address objects whose email address started with the word tony, the usual backref behavior is that all items populate in both directions. We wouldn’t want this behavior for a case like the following:

>>> u1 = User()
>>> a1 = Address(email='mary')
>>> a1.user = u1
>>> u1.addresses
[<__main__.Address object at 0x1411910>]

Above, the Address object that doesn’t match the criterion of “starts with ‘tony’” is present in the addresses collection of u1. After these objects are flushed, the transaction committed and their attributes expired for a re-load, the addresses collection will hit the database on next access and no longer have this Address object present, due to the filtering condition. But we can do away with this unwanted side of the “backref” behavior on the Python side by using two separate relationship() constructs, placing back_populates only on one side:

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    addresses = relationship("Address",
                    primaryjoin="and_(User.id==Address.user_id, "
                        "Address.email.startswith('tony'))",
                    back_populates="user")

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(Integer, ForeignKey('user.id'))
    user = relationship("User")

With the above scenario, appending an Address object to
the .addresses collection of a User will always establish the .user attribute on that Address:

>>> u1 = User()
>>> a1 = Address(email='tony')
>>> u1.addresses.append(a1)
>>> a1.user
<__main__.User object at 0x1411850>

However, applying a User to the .user attribute of an Address, will not append the Address object to the collection:

>>> a2 = Address(email='mary')
>>> a2.user = u1
>>> a2 in u1.addresses
False

Of course, we’ve disabled some of the usefulness of backref here, in that when we do append an Address that corresponds to the criteria of email.startswith(‘tony’), it won’t show up in the User.addresses collection until the session is flushed, and the attributes reloaded after a commit or expire operation. While we could consider an attribute event that checks this criterion in Python, this starts to cross the line of duplicating too much SQL behavior in Python. The backref behavior itself is only a slight transgression of this philosophy - SQLAlchemy tries to keep these to a minimum overall.

Flask-SQLAlchemy 中的 relationship & backref   今天重看 Flask 时,发现对backref仍然没有理解透彻。查阅文档后发现,以前试图孤立地理解backref是问题之源,backref是与relationship配合使用的。 一对多关系 db.relationship()用于在两个表之间建立一对多关系。例如书中 roles 表中一个 User 角色,可以对应 users 表中多个实际的普通用户。实现这种关系时,要在“多”这一侧加入一... 阅读详情

相关推荐

ansible的常用模块

ansible的常用模块一、ansible Ad-Hoc命令集二、ansible的命令参数三、ansible的常用模块1、command模块2、shell模块、script模块3、copy模块、fetch模块4、file模块5、archive模块、unarchive模块6、hostname模块、cron模块 一、ansible Ad-Hoc命令集 1、ansible提供两种方式去完成任务,一是 Ad-Hoc 命令,一是写 ansible playbook。 2、Ad-Hoc更注重于解决一些简单或者平时工作中

S_K15的博客 1958

(翻译玩)SQLALchemy backref章节文档

Linking Relationships with Backref 自从在Object Relational Tutorial中第一次提到backref参数后,许多案例中也用到了backref,那么他到底做了什么?让我们从典型的"用户-地址"模型来探究吧. from sqlalchemy import Integer, ForeignKey, String, Column from s...

weixin_30491641的博客 357

SQLAlchemy 2.0中文文档:ORM升级与异步查询实战

ORM(对象关系映射)是连接数据库与面向对象编程的关键技术,通过抽象SQL操作提升开发效率。SQLAlchemy作为Python生态的主流ORM工具,其2.0版本通过异步IO支持和声明式映射改进实现了性能突破。在物联网等高并发场景下,异步查询可提升30%吞吐量,而新版工作单元模式增强了事务管理的精确性。本文深入解析中文文档的术语标准化策略与异步Session实践,帮助开发者掌握从1.x到2.0的平滑迁移路径,特别针对连接池配置、延迟加载优化等企业级应用痛点提供解决方案。

weixin_34280237的博客 347

SQLAlchemy 在 Flask 应用中的使用和最佳实践

在构建 Python web 应用时,处理数据库是一个不可避免的任务。SQLAlchemy 作为一个强大的 SQL 工具包和对象关系映射(ORM)系统,为 Python 应用提供了高效处理数据库的能力。特别是在 Flask 这类框架中,SQLAlchemy 提供了一个直观的方式来定义数据模型和执行数据库操作。

qq_45430571的博客 1134

Flask-SQLAlchemy多对多关系正确建模与实战

多对多关系是关系型数据库建模的核心概念,其本质并非简单外键绑定,而是需通过独立关联表或关联模型表达双方共同参与的业务事实。理解Flask-SQLAlchemy中db.Table、Association Model与association_proxy三者的语义差异,是避免数据不一致、N+1查询和并发异常的关键。技术价值在于保障参照完整性、支持业务属性扩展(如收藏时间、状态标记)并实现高效JOIN与批量加载。典型应用场景包括用户-标签、课程-章节、商品-分类等,本文聚焦真实业务落地,覆盖从模型定义、迁移、CRU

weixin_30873847的博客 332

Python内存分析实战:从OOM定位到热修复的三层诊断法

Python内存管理是服务稳定性的核心基础,其本质涉及CPython内存分配机制、对象生命周期与进程内存映射的协同作用。理解RSS、USS与Python堆内存的物理边界,是区分真实泄漏与假阳性告警的关键前提;掌握tracemalloc、objgraph和pympler等工具的适用边界与典型陷阱,可避免将mmap文件或C扩展内存误判为Python对象泄漏。该技术广泛应用于高并发Web服务、AI推理后端及数据ETL流水线等对内存敏感的生产场景。本文聚焦真实线上OOM问题,系统拆解进程级监控、对象级追踪与代码级验

FLY_THINK2012的博客 371

SQLAlchemy_定义(一对一/一对多/多对多)关系

SQLAlchemy_定义(一对一/一对多/多对多)关系 目录 BasicRelationshipPatterns One To Many One To One Many To Many Basic Relationship Patterns 基本关系模式The imports used for each of the following sections is a...

weixin_30602505的博客 211

东方财富网 数据访问接口及字段说明

东方财富网 数据访问接口和字段说明

雨中山草 2万+

SQLAlchemy 2.0核心功能与异步数据库操作实践

ORM(对象关系映射)是连接应用程序与数据库的重要技术,通过将数据库表映射为编程语言中的对象,极大简化了数据操作。SQLAlchemy作为Python生态中最成熟的ORM工具,其2.0版本通过统一查询接口和增强异步支持,显著提升了开发效率。在异步编程范式下,结合AsyncIO实现的数据库操作可以大幅提升并发性能,特别适合FastAPI等现代Web框架。本文以SQLAlchemy 2.0为例,详解ORM映射、异步引擎配置等核心功能,并分享在实际项目中解决N+1查询、连接泄漏等典型问题的工程实践。

weixin_30699955的博客 389

保姆级教程:在DolphinScheduler 3.x中配置Apache SeaTunnel任务(Flink/Spark双引擎)

本文提供了一份详细的教程,指导如何在DolphinScheduler 3.x中配置Apache SeaTunnel任务,支持Flink和Spark双引擎。从环境准备、脚本选择到配置文件编写和任务调度优化,涵盖了所有关键步骤和常见问题解决方案,帮助用户高效集成SeaTunnel到海豚调度系统中。

weixin_42524945的博客 194

基于卷积神经网络的人脸表情识别(JAFFE篇)

1.win10/11操作系统2.python3.7以上3.tensorflow2.4以上版本(2.0其它版本需要微调)4.内存12G,显卡4G以上(没有独显倒是也能跑...)(这个可爱的妹子就是JAFFE数据集中的图片)

小林同学的计算机学习 5914

sqlalchemy在python中的使用(表之间的关系)四

本章节介绍SQLAlchemy的表关系,主要分为以下几种 1、一对多关系 2、一对一的关系 3、多对多的关系 一、一对多的关系 在多表关联中,常见的是一对多的关系,但是有时候我们也会听到多对一的关系,其实他们仅仅是站在不同的角度上来看的表关系,(本案例中采用用户与文章来说明) 1、一个用户可以写多篇文章(用户对文章是一对多的关系) 2、文章只能有一个用户(多对一的关系) 具体的代码实...

weixin_34248487的博客 204

游戏“中台”的故事——架构演进、团队协同与产品创新的深度剖析

什么是中台?在游戏行业里,中台并不是把所有技术都归口管理、统一“圈养”。更不是简单的工具集合。它代表的,是一种“模块化底座”——把业务的通用能力、基础支撑和数据结合,变成可复用、可扩展、可创新的技术体系。让“前台”专注于创新玩法、极致体验;让“后台”稳健保障数据、安全、性能;让“中台”统合各种资源、流程、工具,形成平台型生产力。游戏中台是团队协同、技术创新、业务增长并行的产物。它让开发从重复劳动解脱,带着创新冲锋;让运营靠数据说话,精准制胜;让产品实现高效迭代,生态爆发。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1950

在Flask中操作数据库

转自:一只在当地较为英俊的程序猿 前言 Web程序最常用基于关系模型的数据库,这种数据库也称为SQL数据库,因为它们使用结构化查询语言。关系型数据库把数据存储在表中,表模拟程序中的不同实体。简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。 关系模型中常用的概念: 关系:可以理解为一张二维表,每个关系都具有一个关系名,就是通常说的表名...

LYLLOAD的专栏 2519

Codex CLI 手机号验证失败?5 种接码平台实测对比与绕过地区限制的 3 步操作

揭示 Codex CLI 手机号验证失败的真实原因在于上下文污染而非网络问题,分析其通过 ASN、Accept-Language 和 TLS SNI 三重加权风控的机制,并实测对比 5 种接码平台在 DNS 解析路径、ASN 干净度和复用间隔上的差异,提出剥离浏览器指纹、固化 TLS SNI、隔离

weixin_42627902的博客 732

工业视觉降本300%实战:C# + 开源YOLO如何干掉Halcon/VisionPro?

在当前制造业普遍追求“降本增效”的大背景下,工业视觉检测系统作为产线的眼睛,其成本问题日益突出。通过该方案,我们成功帮助一家电子厂将单条产线的视觉检测成本从15万降低至不足5千(主要为工控机硬件成本),降本幅度超过95%,且系统稳定性经受住了6个月连续生产的考验。:C#负责“工程化”和“业务逻辑”,YOLO负责“智能算法”,二者结合,完美覆盖了工业视觉从算法到落地的全链路。的组合,构建一套高性能、低成本、易维护的工业视觉解决方案,并彻底替代昂贵的付费库。” 这是一个典型的误区。工业相机/USB相机。

2601_94871597的博客 430

基于Flask的音乐平台全栈开发:从零构建毕业设计项目

Web开发的核心在于构建功能完整、数据驱动的交互式应用,其原理通常遵循MVC(模型-视图-控制器)或MTV(模型-模板-视图)架构模式,通过处理HTTP请求、操作数据库和渲染页面来实现业务逻辑。这种模式的技术价值在于清晰分离关注点,提升代码可维护性和可扩展性,是构建中小型应用的理想选择。在众多技术栈中,Python的Flask框架以其轻量、灵活和易于上手的特点,成为快速实现全栈项目的热门工具,尤其适合需要集成文件上传、用户认证和数据管理等常见功能的应用场景。例如,开发一个音乐平台就涉及文件上传与流媒体播放、

weixin_34221073的博客 398

R语言 地理加权随机森林(GWRFC )

随机森林可以产生高准确度的分类器,被广泛用于解决模式识别问题。然而,随机森林赋予每个决策树相同的权重,这在一定程度上降低了整个分类器的性能。该算法引入二次训练过程,提高分类正确率高目前,鲜有中文文章介绍GWRFC的技术文档,作者想使用该方法时会遇到重重困难,因此有必要利用R来建模,通过流程演示,供读者参阅。............

qingchen98的博客 6632

Python自动化构建小说追更系统:Flask+情感分析+定时任务

网络爬虫与自动化脚本是Python在数据获取与处理领域的核心应用,其原理是通过模拟浏览器行为抓取网页数据,并结合解析库提取结构化信息。这项技术的价值在于能够将重复性的人工操作转化为高效、准确的自动化流程,广泛应用于内容聚合、市场监控与数据分析等场景。本文以构建一个小说连载追踪系统为例,演示如何整合Requests、BeautifulSoup进行内容抓取,利用Flask搭建本地Web管理界面,并引入基于BERT的情感分析模型对章节内容进行‘甜度’量化。通过配置系统级定时任务,最终实现一个集自动检查更新、内容存

weixin_30247307的博客 321

100天精通Python(爬虫篇)——第119天:基于selenium实现隐藏浏览器指纹特征(反反爬策略)

1. 什么是浏览器指纹? 2. 爬虫隐藏浏览器指纹特征的好处? 3. 手动打开浏览器指纹情况 4. 无界面模式打开浏览器 5. 脚本隐藏浏览器指纹特征

努力让自己发光,对的人才能迎着光而来 8万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

上一篇: Flask学习记录之Flask-Admin
下一篇: GIT学习笔记
agmcs
博客等级 码龄13年 7粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值