SQLAlchemy关联表一对多关系的详解

news2024/12/23 23:32:54

目录

ORM关系之一对多

示例1 

代码刨析 

示例2

 代码刨析


ORM关系之一对多

mysql级别的外键,还不够爽,必须拿到一个表的外键,然后通过这个外键再去另外一张表中查找,这样太麻烦了。

SQLAlchemy提供了一个relationship,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问得到了。

另外,可以通过backref来指定反向访问的属性名称。newss是指有多篇新闻。他们之间的关系是一个“一对多”的关系。

数据库层面

在数据库中,一对多关系通常通过在多的一方表中添加一个外键列,该列引用了另一方的主键。例如,在一个博客系统中,一个用户可以有多篇文章,那么在文章表中通常会包含一个指向用户表的外键。

ORM 层面

在 ORM 中,一对多关系通常通过在一个类中定义一个关联属性来实现。这个关联属性指明了与之相关联的类,以及在数据库中如何表示这种关系。

在 SQLAlchemy 中,可以使用 relationship 来定义一对多关系。比如:

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String, unique=True, nullable=False)
    articles = relationship('Article', back_populates='author', cascade='all, delete-orphan')

class Article(Base):
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    author_id = Column(Integer, ForeignKey('users.id'))
    author = relationship('User', back_populates='articles')

查询操作 

在一对多关系中,可以轻松地通过关联属性来访问相关联的对象。例如,你可以通过 user.articles 访问一个用户的所有文章,或者通过 article.author 访问一篇文章的作者。

# 获取第一个用户的所有文章
user = session.query(User).first()
articles = user.articles

# 获取第一篇文章的作者
article = session.query(Article).first()
author = article.author

添加与删除 

在一对多关系中,你可以通过调用关联属性来添加新的对象。例如,你可以通过 user.articles.append(new_article) 将一篇新文章添加到一个用户的文章列表中。

# 创建一个新的文章,并将其关联到第一个用户
new_article = Article(title='New Article', content='Content of the new article')
user.articles.append(new_article)
session.commit()

还可以通过 user.articles.remove(article) 删除一个用户的某篇文章。

# 删除用户的第一篇文章
article_to_delete = user.articles[0]
user.articles.remove(article_to_delete)
session.commit()

以下是一个简单的示例,使用 SQLAlchemy 来创建一个用户和文章的一对多关系:

示例1 

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

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String, unique=True, nullable=False)
    articles = relationship('Article', back_populates='author', cascade='all, delete-orphan')

class Article(Base):
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    author_id = Column(Integer, ForeignKey('users.id'))
    author = relationship('User', back_populates='articles')

# 创建数据库连接
engine = create_engine('sqlite:///example.db')

# 创建表格
Base.metadata.create_all(engine)

代码刨析 

在这个示例中,我们定义了两个类:UserArticle,并建立了一对多的关系:

  • User 类拥有一个属性 articles,它是一个关系属性,通过 relationship 函数来定义。这个关系会映射到 Article 类,并且通过 back_populates 参数指定了反向关系的属性名为 author

  • Article 类中有一个属性 author,也是一个关系属性,通过 relationship 函数定义。它映射到 User 类,并且通过 back_populates 参数指定了反向关系的属性名为 articles

在这个示例中,我们通过 relationship 来定义了一对多关系,并且通过 ForeignKey 来建立了外键关系,将 Article 表中的 author_idUser 表中的 id 关联起来。

这样,一个用户可以拥有多篇文章,而每篇文章只属于一个用户。

示例2

from sqlalchemy import Column,Integer,String,Text,ForeignKey
from sqlalchemy.orm import relationship


from db_util import Base,Session


class User(Base):
  __tablename__ = 't_user'
  id = Column(Integer,primary_key=True,autoincrement=True)
  uname = Column(String(50),nullable=False,name='name')
  # news = relationship('News')  # 不友好
  
  def __repr__(self):
    return f'<User: id={self.id} uname={self.uname}>'
    
# 1对多 ForeignKey的关键字要建立在 多一边
class News(Base):
  __tablename__ = 't_news'
  id = Column(Integer,primary_key=True,autoincrement=True)
  title = Column(String(50),nullable=False)
  content = Column(Text,nullable=False)
  uid = Column(Integer,ForeignKey('t_user.id'))
  
  user = relationship('User',backref='news') # 将主表的数据注入到这个字段


  def __repr__(self):
    return f'<News: id={self.id} title={self.title} content={self.content} uid={self.uid}>'


def create_data():
  user = User(uname = 'sxt') 
  news1 = News(title='Python',content='flask',uid = 1)
  news2 = News(title='MySQL',content='SQL',uid = 1)


  with Session() as ses:
    ses.add(user)
    ses.commit()


  with Session() as ses:
    ses.add(news1)
    ses.add(news2)
    ses.commit()


def query_data():
  with Session() as ses:
    # news1 = ses.query(News).first()
    # print(news1)
    
    # select u.id u.uname from t_news n left join t_user u n.uid = u.id where n.id = 1;
    news1 = ses.query(News).first()
    uid = news1.uid
    user = ses.query(User).first()
    print(user)




def query_data2():
  # 通地子表查询主表的数据
  with Session() as ses:
    news1 = ses.query(News).first()
    print(news1.user)




def query_data3():
  # 通地主表查找子表的数据
  with Session() as ses:
    user1 = ses.query(User).first()
    print(user1.news)




if __name__ == '__main__':
  # Base.metadata.create_all()
  # create_data()
  # query_data()
  # query_data2()
  query_data3()

 代码刨析

  1. User 类中包括了一个关联属性 news,它通过 relationship 来指明与 News 类的关系。而在 News 类中,使用了 ForeignKey 来建立了对 User 表的外键关联,并通过 relationship 指定了与 User 类的关联关系。

  2. create_data 函数创建了一个用户和两条新闻,并将它们添加到数据库中。

  3. query_data 函数中,你首先查询了一条新闻,然后获取了它的 uid(用户ID),接着通过用户ID查询了相应的用户。

  4. query_data2 函数中,首先查询了一条新闻,然后通过 news1.user 直接访问了与之关联的用户对象。

  5. query_data3 函数中,首先查询了一个用户,然后通过 user1.news 直接访问了与之关联的新闻对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1044489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件工程第三周

可行性研究 续 表达工作量的方式 LOC估算&#xff1a;Line of Code 估算公式S(Sopt4SmSpess)/6 FP&#xff1a;功能点 1. LOC (Line of Code) 估算 定义&#xff1a;LOC是指一个软件项目中的代码行数。 2. FP (Function Points) 估算 定义&#xff1a;FP是基于软件的功能性和…

H5类似易企秀/编辑器/页面制作/开发/生成工具/软件/源码/授权

概述 H5DS (HTML5 Design software) 这是一款基于WEB的 H5制作工具。让不会写代码的人也能轻松快速上手制作H5页面。 详细 项目简介 H5DS (HTML5 Design software) 这是一款基于WEB的 H5制作工具。让不会写代码的人也能轻松快速上手制作H5页面。H5DS 官方 Git (GitHub - h5…

XC3110 高性能、低成本离线式PWM功率开关 可用于小家电电源 辅助电源 最大200MA的电流

XC3110是一款非隔离型、高集成度且低成本的PWM功率开关&#xff0c;适用于降压型和升降压型电路。 XC3110采用高压单晶圆工艺&#xff0c;在同一片晶圆上集成有500V 高压 MOSFET 和采用开关式峰值电流模式控制的控制器。在全电压输入的范围内可以保证高精度的5V 默认输出。在芯…

C#设置自动关机

功能&#xff1a;自动设置电脑关机时间&#xff0c;可取消 创建一个shutdown函数&#xff0c;bool isCancle&#xff0c;传入值为ture就取消关机&#xff0c;interval间隔时间&#xff0c;unit不带符号的整型 private static void ShutdownPC(bool isCancel, uint interval){P…

A*搜索算法

前言 这个我也不知道算不算是A*搜索算法&#xff0c;可能只是A搜索算法。 首先看相关的定义&#xff1a; 启发式搜索在搜索过程中根据启发信息评估各个节点的重要性&#xff0c;优先搜索重要的节点。 估价函数的任务就是估计待搜索节点“有希望”的程度。 估价函数f(n)定义…

vue 实现数字验证码功能

需求&#xff1a;写了一个 手机发送验证码后 输入固定验证码的功能 封装成一个组件,如下: <template><div class"conts"><div class"box"><div class"code_list"><div :class"[ code_item, hideIndex 0 ? co…

Ubuntu Qt 5.15.2 支持 aarch64

概述 AArch64是ARMv8 架构的一种执行状态。 为了更广泛地向企业领域推进&#xff0c;需要引入64 位构架。 同时也需要在ARMv8 架构中引入新的AArch64 执行状态。 AArch64 不是一个单纯的32 位ARM 构架扩展&#xff0c;而是ARMv8 内全新的构架&#xff0c;完全使用全新的A64 指令…

软件设计模式——外观模式

摘要 本文主要分析设计模式 - 结构型 - 外观(Facade)&#xff0c;它提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口&#xff0c;从而让子系统更容易使用。 一、外观模式的意图 提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口&#xff0c;从而让…

2023蓝帽杯半决赛取证复现

1.检材数据开始提取是今年什么时候&#xff1f;&#xff08;答案格式&#xff1a;04-12 13:26&#xff09; 09-11 17:21 这题做错了 其实当时盘古石手机取证里面就有的&#xff0c;想多了去看了日志文件 是真的有点歧义&#xff0c;20分就开始提取任务了 2.嫌疑人手机SD卡存…

TLS/SSL(七) 非对称密码应用 之DH密钥交换协议

一 DH密钥交换协议 DH密钥交换协议用来沟通协商出后面AES算法的密钥,是广泛使用、安全的密钥交换协议 ① RSA密钥交换 备注&#xff1a; RSA算法没有前向保密性&#xff0c;所以TLS1.3及以后的协议禁止RSA作为密钥协商算法 如何理解前向保密性 故事&#xff1a; 斯诺登事…

Spring Cloud Alibaba Seata 搭建以及分布式事务的验证

文章目录 Spring Cloud Alibaba Seata 搭建以及分布式事务的验证1.seata 简介2. seata的三大角色3. Seata的流程4. Seata AT模式5. Seata搭建找到模板案例&#xff0c;照着抄6. Seata Client快速开始6.1 声明式事务实现&#xff08;GlobalTransactional&#xff09;6.2 添加依赖…

【牛客网】倒置字符串

思路 首先将整个字符串逆序,再分别将每个单词逆序 代码 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void reverse(int begin, int end, char[] array){while(begin < end){char temp array[begin…

第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 试题 A: 子 2023

[蓝桥杯 2023 国 B] 子 2023 试题 A: 子 2023 【问题描述】 小蓝在黑板上连续写下从 1 1 1 到 2023 2023 2023 之间所有的整数&#xff0c;得到了一个数字序列&#xff1a; S 12345678910111213 ⋯ 20222023 S 12345678910111213\cdots 20222023 S12345678910111213⋯2…

USB到UART桥接控制器——GP232RNL

GP232RNL是一款高度集成的USB到UART桥接控制器&#xff0c;提供了一种简单的解决方案&#xff0c;可以使用最少的元器件和PCB空间&#xff0c;将RS232接口转换为USB接口。GP232RNL包括一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整的调制解调器控制信号的异…

Python完整教程

Python由荷兰国家数学与计算机科学研究中心的吉多范罗苏姆于1990年代初设计&#xff0c;作为一门叫作ABC语言的替代品。 [1] Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释型语言的本质&#xff0c;使它成…

【Hash表】无重复字符的最长字串-力扣 3 题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

中国TO B投资,迈入第二周期

2023年,中国TOB正在愈发成熟,迈进第二个周期的趋势已经体现在融资金额上。 作者|斗斗 编辑|皮爷 出品|产业家 TOB&#xff0c;依旧是一级市场的大热门。 统计数据显示&#xff0c;截止2023年8月31日&#xff0c;TOB领域共发生融资事件406起&#xff0c;同比2022年减少…

人工智能核心基础 - 规划和概要

Hi&#xff0c;你好。又见面咯&#xff0c;我是茶桁。 在之前&#xff0c;我花了两个来月的时间撰写了「Python篇」和「数学篇」&#xff0c;希望小伙伴们在正式进入AI之前能够打好一个基础。那么今天开始&#xff0c;我们将正式开始AI基础的学习。 这一节课咱们先不着急直接…

细胞机器人系统中的群体智能

摘要 细胞机器人系统具有“智能”行为能力。本文分析了这种智能的含义。本文根据上述不可思议智能行为的不可预测性来定义机器人智能和机器人系统智能。对不可预测性概念的分析与&#xff08;1&#xff09;统计不可预测、&#xff08;2&#xff09;不可访问、&#xff08;3&am…

STL中string类的实现

目录 引入 构造 | 析构函数 构造函数 析构函数 返回指针的c_str() 求字符大小的size() operator[] 普通对象调用&#xff1a; const对象调用&#xff1a; 迭代器的实现 范围for 深浅拷贝 浅拷贝的不足 实现深拷贝 赋值的深拷贝 传统写法与现代写法 传统写法 现…