【问题标题】:how to use many-to-many in sqlalchemy如何在 sqlalchemy 中使用多对多
【发布时间】:2011-07-25 19:02:26
【问题描述】:

我想在我的项目中使用来自 sqlalchemy 的关系。我在简单的代码上测试多对多:

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


engine = create_engine('sqlite:///m2m.sqlite', echo=True)

Base = declarative_base(engine)

post_tags = Table('post_tags', Base.metadata,
                Column('post_id', Integer, ForeignKey('blog_posts.id')),
                Column('tag_name', String, ForeignKey('blog_tags.name'))
)

class BlogPost(Base):
    __tablename__ = 'blog_posts'

    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String)
    content = Column(Text)
    created = Column(DateTime, default=datetime.now)   

    tags = relationship('BlogTag', secondary=post_tags, backref='blog_posts')

    def __init__(self, title, content, tags=None):
        self.title = title
        self.content = content
        if tags:
            self.tags = tags

    def __repr__(self):
        return '%d %s %s' % (self.id, self.title, self.content)

class BlogTag(Base):
    __tablename__ = 'blog_tags'

    name = Column(String, primary_key=True)

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return '%s' % self.name

Base.metadata.create_all(engine)

Session = sessionmaker(engine)
dbs = Session()

post = BlogPost('1', '1111', [BlogTag('one'), BlogTag('two')])
dbs.add(post)
dbs.commit()

post = BlogPost('2', '222', [BlogTag('one'), BlogTag('newtag')])
dbs.add(post)
dbs.commit()

for x in dbs.query(BlogTag).all():
    print x

但我在代码上遇到异常:

post = BlogPost('2', '222', [BlogTag('one'), BlogTag('newtag')])
dbs.add(post)
dbs.commit()

如果表中已经存在标签,如何将新的博客文章插入数据库?


感谢大家。我为 BlogTag 编写以下代码:

class BlogTag(Base):
    __tablename__ = 'blog_tags'

    name = Column(String, primary_key=True)

    @staticmethod
    def get(dbsession, name):
        obj = dbsession.query(BlogTag).filter(BlogTag.name == name).first()
        if not obj:
            obj = BlogTag(name)
        return obj

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return '%s' % self.name

我像下面这样使用它们:

tags = [BlogTag.get(dbs, 'one'), BlogTag.get(dbs, 'two')]

post = BlogPost('1', '1111', tags)
dbs.add(post)
dbs.commit()

tags = [BlogTag.get(dbs, 'one'), BlogTag.get(dbs, 'newtag')]
post = BlogPost('2', '222', tags)
dbs.add(post)
dbs.commit()

我不确定这是不是最好的方法,但它有效:)

我可以从 Base 获取会话吗?

【问题讨论】:

  • 您也可以发布实际的异常吗?
  • 不,您无法从BaseAFAIK 参加会议。

标签: python database sqlalchemy


【解决方案1】:

这里的问题是你创建了两个BlogTag对象,主键为one

SQLAlchemy 的会话对象无法知道它不应该为您创建的第二个对象创建新的数据库行。

以下将起作用:

tag_one = BlogTag('one')
post = BlogPost('1', '1111', [tag_one, BlogTag('two')])
dbs.add(post)
dbs.commit()

post = BlogPost('2', '222', [tag_one, BlogTag('newtag')])
dbs.add(post)
dbs.commit()

您还可以执行以下操作(但请注意,dbs.query(BlogTag).get('one') 将对数据库执行额外的 SELECT,在第一个示例中不需要):

post = BlogPost('1', '1111', [BlogTag('one'), BlogTag('two')])
dbs.add(post)
dbs.commit()

post = BlogPost('2', '222', [dbs.query(BlogTag).get("one"), BlogTag('newtag')])
dbs.add(post)
dbs.commit()

【讨论】:

    【解决方案2】:

    BlogPost('one') 创建全新的对象。您必须改为从数据库中获取现有标签。

    另外,在上面的示例中,您忘记向数据库会话添加新标签。

    【讨论】:

      猜你喜欢
      • 2011-04-06
      • 2023-03-03
      • 2017-04-03
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 2014-05-18
      • 2022-07-07
      相关资源
      最近更新 更多