gpt4 book ai didi

python - 如何在flask-sqlalchemy中创建过程中创建并关联另一个模型?

转载 作者:太空宇宙 更新时间:2023-11-03 17:25:51 24 4
gpt4 key购买 nike

我有一对多关系,我想创建相关模型并将其关联到创建时创建的模型。

这里我有 UserItem 模型。第一次创建用户时,用户应该自动获得一个默认项目:

class User(Model):
id = Column(Integer, primary_key=True)
name = Column(String, default="", unique=True)
items = relationship('Item', backref='user', lazy='dynamic')

def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
self.items.append(...) # <---- Add default item here?

class Item(Model):
id = Column(Integer, primary_key=True)
name = Column(String, default="")
userid = Column(Integer, ForeignKey('user.id'))

但我不确定如何在 User.__init__() 中附加新项目?是不是类似:

# in User __init__()
item = Item(name="default item")
self.items.append(item)
session.add(item)

但是我不清楚如果任一模型出现故障,事务会发生什么,以及我是否需要调用 session.add(item) 或者是否将项目自动附加到用户会执行此操作.

即,当我创建用户时事务会发生什么,并且这会引发错误,因为 name 不是唯一的。还会创建该项目吗?

def doit():
myuser = User(name='bob') # <---- Say "bob" is already in DB
session.add(myuser)
session.commit()

在用户创建时为用户创建默认项目的有效方法是什么?

最佳答案

解决这些类型问题的最佳方法是创建一些测试代码。我发现 sqlite 内存数据库中的原型(prototype)设计效果非常好。

因此,如果关系配置正确 - 就像您的情况一样 - sqlalchemy 将找出键关系并自动设置外键。

但是眼见为实,我添加了一些示例代码,其中包含针对您描述的场景的单元测试。在每次测试之前,我都会删除并重新创建所有表以确保架构干净。

import logging
logging.basicConfig()

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()


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


class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String, default="", unique=True)
items = relationship('Item', backref='user', lazy='dynamic')

def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
self.items.append(Item(name='DefaultItem'))


class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
name = Column(String, default="", unique=True) # Unique so we can create a failing test
user_id = Column(Integer, ForeignKey('user.id'))


from sqlalchemy import create_engine
from sqlalchemy.orm.session import sessionmaker
from contextlib import contextmanager


engine = create_engine('sqlite://', echo=True)
Session = sessionmaker(bind=engine)


@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()


import unittest


class Test(unittest.TestCase):
def setUp(self):
Base.metadata.create_all(engine) # Reset

def tearDown(self):
Base.metadata.drop_all(engine) # Reset

def test_sanity(self):
with session_scope() as session:
self.assertEqual(session.query(User).all(), [])
self.assertEqual(session.query(Item).all(), [])

def test_item_automatically_added(self):
with session_scope() as session:
user = User(name='John')
session.add(user)

with session_scope() as session:
user = session.query(User).filter(User.name == 'John').one()
self.assertIsNotNone(user.items.filter(Item.name == 'DefaultItem').one())

def test_duplicate_item_causes_user_save_to_fail(self):
with session_scope() as session:
item = Item(name='DefaultItem')
session.add(item)

from sqlalchemy.exc import IntegrityError

with self.assertRaises(IntegrityError):
with session_scope() as session:
user = User(name='John')
session.add(user)


if __name__ == '__main__':
unittest.main()

所以这些测试涵盖了除一个场景之外的所有场景。如果用户创建失败,测试将失败。我想不出一个简单的方法来进行此测试,但我确实检查了 sql echo 输出

INFO:sqlalchemy.engine.base.Engine:INSERT INTO user (name) VALUES (?)
2015-09-15 20:55:49,834 INFO sqlalchemy.engine.base.Engine INSERT INTO user (name) VALUES (?)
INFO:sqlalchemy.engine.base.Engine:('John',)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO item (name, user_id) VALUES (?, ?)
2015-09-15 20:55:49,834 INFO sqlalchemy.engine.base.Engine ('John',)
INFO:sqlalchemy.engine.base.Engine:('DefaultItem', 1)
2015-09-15 20:55:49,834 INFO sqlalchemy.engine.base.Engine INSERT INTO item (name, user_id) VALUES (?, ?)

用户总是插入在项目之前,因此我们无论如何都无法获得悬空的项目。为了更加确定这一点,您可以将 item.user_id 外键设为不可为空。

关于python - 如何在flask-sqlalchemy中创建过程中创建并关联另一个模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32569219/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com