SQLAlchemy定义数据表关系

一对多

采用作者和文章,一个作者可以有多篇文章,一篇文章只能有一个作者(暂不考虑合著的情况)。

一般在“一”的一方定义关系:

articles = relationship('Article',backref='author')

查询时articles属性会以列表的形式返回该作者的所有文章。

一般在“多”的一方定义外键:

author_id=Column(Integer,ForeignKey('tb_authors.id'))

创建数据时如果是从一的一方建立,在外键列有SQLAlchemy维护,不用手动添加:

author = Author(name='Jack')
author2 = Author(name='Susan')
article1 = Article(title='hello', content='world')
article2 = Article(title='hello', content='python')
article3 = Article(title='hello', content='java')

author.articles.append(article1)
author.articles.append(article2)
author2.articles.append(article3)
session.add(author)
session.add(author2)
session.commit()

此时作者数据表中的内容为:

文章数据表中的内容为:

 

完整代码如下:

rom sqlalchemy import DateTime, Table, Column, String, create_engine, Integer, MetaData, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

base = declarative_base()
engine = create_engine('sqlite:///demo.sqlite3')


class Author(base):
    __tablename__ = 'tb_authors'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String, nullable=False)
    created_on = Column(DateTime, default=datetime.now)
    updated_on = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    articles = relationship('Article', backref='author')

    def __repr__(self):
        return f'<Author: {self.name}>'


class Article(base):
    __tablename__ = 'tb_articles'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    author_id = Column(Integer, ForeignKey('tb_authors.id'))

    def __repr__(self):
        return f'<Article: {self.title}: {len(self.content)} letters>'


base.metadata.create_all(engine)

maker = sessionmaker(bind=engine)
session = maker()

author = Author(name='Jack')
author2 = Author(name='Susan')
article1 = Article(title='hello', content='world')
article2 = Article(title='hello', content='python')
article3 = Article(title='hello', content='java')

author.articles.append(article1)
author.articles.append(article2)
author2.articles.append(article3)
session.add(author)
session.add(author2)
session.commit()

a = session.query(Author).first()
print(a.articles)

一对一 

采用国家和首都,一个国家只能有一个首都,一个首都也只能属于一个国家。

一对一可以视为特殊的一对多。只不过在定义关系的一方(国家或首都均可,一般从国家方定义)应该明确的声明不使用集合(列表)而使用标量。

capital = relationship('Capital',backref='country',userlist=False)

 另一方依然定义外键:

country_id = Column(Integer,ForeignKey('tb_country.id'))

同样如果从国家一方建立数据,首都表中的外键列内容由SQLAlchemy维护:

co1 = Country(name='China')
city1 = Capital(name='Beijing')
co1.capital = city1
co2 = Country(name='Japan')
city2 = Capital(name='Tokyo')
co2.capital = city2
co3 = Country(name='Korea')
city3 = Capital(name='Seoul')
co3.capital = city3
session.add(co1)
session.add(co2)
session.add(co3)
session.commit()

此时国家表中的数据为:

首都表中的数据为:

 

完整代码如下:

from sqlalchemy import DateTime, Table, Column, String, create_engine, Integer, MetaData, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

base = declarative_base()
engine = create_engine('sqlite:///demo.sqlite3')


class Country(base):
    __tablename__ = 'tb_country'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String, nullable=False)
    created_on = Column(DateTime, default=datetime.now)
    updated_on = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    capital = relationship('Capital', backref='country', uselist=False)

    def __repr__(self):
        return f'<Country: {self.name}>'


class Capital(base):
    __tablename__ = 'tb_capital'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String, nullable=False)
    country_id = Column(Integer, ForeignKey('tb_country.id'))
    created_on = Column(DateTime, default=datetime.now)
    updated_on = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    def __repr__(self):
        return f'<Capital: {self.name}>'


base.metadata.create_all(engine)
maker = sessionmaker(bind=engine)
session = maker()

co1 = Country(name='China')
city1 = Capital(name='Beijing')
co1.capital = city1
co2 = Country(name='Japan')
city2 = Capital(name='Tokyo')
co2.capital = city2
co3 = Country(name='Korea')
city3 = Capital(name='Seoul')
co3.capital = city3
session.add(co1)
session.add(co2)
session.add(co3)
session.commit()

cs = session.query(Country).all()
for c in cs:
    print(f'{c.name}:{c.capital}')

 多对多

采用博客和标签,一篇博客可以有多个标签,一个标签也可以被多个博客所拥有。

关系型数据库描述多对多关系时必须有一张关系表。关系表一般就三列:id列,博客的id,标签的id。关系表利用SQLAlchemy提供的Table类直接创建,表中数据由SQLAlchemy自动维护:

blog_tag = Table('tb_blog_tag', base.metadata,
                 Column('id', Integer, primary_key=True, autoincrement=True),
                 Column('blog_id', Integer, ForeignKey('tb_blogs.id')),
                 Column('tag_id', Integer, ForeignKey('tb_tags.id')))

blog_tag变量引用通过Table类创建出来的名为tb_blog_tag的数据表。

在任意一方创建关系说明(博客或标签均可,一般从博客方),创建关系说明时通过secondary属性明确指定关系表的名称:

tags =relationship('Tag',backref='blogs',secondary=blog_tag)

从博客一方创建数据:

b1 = Blog(title='hello', content='world')
b2 = Blog(title='football', content='world cup')
b3 = Blog(title='cat', content='meow meow')
tag1 = Tag(name='Tech')
tag2 = Tag(name='Funny')
tag3 = Tag(name='News')
tag4 = Tag(name='Daily')
tag5 = Tag(name='Pets')
b1.tags.append(tag1)
b1.tags.append(tag2)
b1.tags.append(tag3)
b2.tags.append(tag3)
b2.tags.append(tag4)
b3.tags.append(tag2)
b3.tags.append(tag5)
session.add(b1)
session.add(b2)
session.add(b3)
session.commit()

此时关系表数据为:

数据由SQLAlchemy维护。

博客表数据为:

标签表数据为:

 

完整代码如下:

from sqlalchemy import DateTime, Table, Column, String, create_engine, Integer, MetaData, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

base = declarative_base()
engine = create_engine('sqlite:///demo.sqlite3')

blog_tag = Table('tb_blog_tag', base.metadata,
                 Column('id', Integer, primary_key=True, autoincrement=True),
                 Column('blog_id', Integer, ForeignKey('tb_blogs.id')),
                 Column('tag_id', Integer, ForeignKey('tb_tags.id')))


class Blog(base):
    __tablename__ = 'tb_blogs'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    created_on = Column(DateTime, default=datetime.now)
    updated_on = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    tags = relationship('Tag', backref='blogs', secondary=blog_tag)

    def __repr__(self):
        return f'<Blog: {self.title} {len(self.content)} letters>'


class Tag(base):
    __tablename__ = 'tb_tags'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String, nullable=False)

    def __repr__(self):
        return f'<Tag: {self.name}>'


base.metadata.create_all(engine)
maker = sessionmaker(bind=engine)
session = maker()

b1 = Blog(title='hello', content='world')
b2 = Blog(title='football', content='world cup')
b3 = Blog(title='cat', content='meow meow')
tag1 = Tag(name='Tech')
tag2 = Tag(name='Funny')
tag3 = Tag(name='News')
tag4 = Tag(name='Daily')
tag5 = Tag(name='Pets')
b1.tags.append(tag1)
b1.tags.append(tag2)
b1.tags.append(tag3)
b2.tags.append(tag3)
b2.tags.append(tag4)
b3.tags.append(tag2)
b3.tags.append(tag5)
session.add(b1)
session.add(b2)
session.add(b3)
session.commit()

bs = session.query(Blog).all()
for b in bs:
    print(b, end=' ')
    print(b.tags)

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值