【问题标题】:Avoid DB Session addition marshmallow object while using marshmallow sql-alchemy object使用棉花糖 sql-alchemy 对象时避免 DB Session 添加棉花糖对象
【发布时间】:2016-08-01 18:30:27
【问题描述】:

有没有办法避免在使用 Marshmallow - sqlalchemy 时将数据插入会话中

sqlalchemy marshmallow 避免加载到会话中

参考:https://marshmallow-sqlalchemy.readthedocs.org/en/latest/

因为我们试图自己管理对象。如果需要,将添加到会话中,但为了验证我需要使用 load()

author = Author(name='Chuck Paluhniuk')
book = Book(title='Fight Club', author=author)
session.add(author)
session.add(book)
session.commit()

author_schema.dump(author).data
# {'books': [123], 'id': 321, 'name': 'Chuck Paluhniuk'}

author_schema.load(dump_data, session=session).data
# <Author(name='Chuck Paluhniuk')>

为了避免这个问题,在我尝试加载之后,我可以调用 DB Session.close() 来忽略临时数据。但我再次需要让会话将数据刷新到 DB 中。

请指教。感谢您的帮助

【问题讨论】:

  • 这个例子所指的会话不是 Flask 客户端会话实现。此示例所指的会话是 Flask 应用程序与其数据库的会话。
  • 是的@Snuggert你是对的。我只是举例。我很好地将会话传递给 marshmallow sqlalchemy 。唯一的问题是在验证后使用 .loads() 时,它会将数据放入 Session 。注意:Marshmallow-sqlalchemy 必须要求将会话从 DB 模型转换为 Marshmallow 模型。
  • @Shankar 您是否考虑过在没有 SQLAlchemy 集成的情况下使用 marshmallow
  • @mam8cc 是的,我们在项目中单独使用棉花糖和 sqlalchemy。我正在寻找集成这些的方法,因为我们需要为 DB 和 REST 服务定义单独的模型。
  • @Shankar 所以您想要一种方法来表示数据库中的数据,但要从您的 API 编组不同的表示?

标签: python flask sqlalchemy flask-sqlalchemy marshmallow


【解决方案1】:

将对象添加到session 对您的代码没有不良影响。正如你所说,你以后会自己做。所以手动添加和load方法添加没有区别。

author = author_schema.load(dump_data, session=session)
# now author has been added to session by load method
# do whatever you want
db.session.commit() # This is enough to write changes you've made
# or if you don't want to save anything just
db.session.rollback()

我真的不明白你为什么要阻止通过load 的方法将对象添加到会话中

【讨论】:

  • 感谢您的建议。甚至我们可以使用 db.session.close() 从会话中删除我不想解决的对象。将对象添加到会话中会产生效果,我将尝试解释。不同之处在于我仅将加载方法用于验证,如果出现问题,我们会将错误抛出给用户。对象包含部分数据,假设我需要将数据发布到第三方服务,只有当它成功时我需要将数据放入数据库。否则,我可以提出错误。我不希望 load() 方法将数据放入会话中。请添加您的想法,如果您有任何问题,请告诉我。
  • 正如我所见,如果数据有效,您就可以了。如果数据无效,您可以通过调用session.rollback() 简单地丢弃会话中的对象,并且使用回滚方法不是一个坏选择。即使它是一个http API,会话对于每个请求都是一个新的。所以即使你对会话中的数据不做任何事情,也不会发生任何不好的事情
  • 是的,你是对的,说我正在实现这个我知道细节,如果一个新的开发者错过了新 API 中的 session.rollback()/db.session.close() 那么坏数据由于最后的自动提交,将在数据库中。我对么 ?我看到这更容易出错。请指教
  • 嗯。是的,它可能会发生。您可能想要提供一个函数甚至是一个装饰器来进行验证,它将用于每次验证,并且在出现无效数据的情况下它会自动清除会话。但你永远不能 100% 肯定地防止错误。
  • 是的,这是真的。非常感谢您的建议。我脑子里也有同样的解决方案,我可以提供那个装饰器,但我认为我试图解决的问题很简单,避免重复模式(DB & REST marshmallow 模式)。会导致很多并发症。现在我不打算添加装饰器,因为这个解决方案需要两个会话而不是直接进行。而是为每个 API 维护两个模式,如果您有任何其他解决方案,请建议我
【解决方案2】:

对架构的load() 的调用不会自动将对象添加到会话中:

>>> from models import session
>>> from schema import author_schema
>>> a = {'id': 1, 'name': 'Chuck Paluhniuk'}
>>> obj = author_schema.load(a, session=session)
>>> session.new
IdentitySet([])
>>> session.add(obj.data)
>>> session.new
IdentitySet([<Author(name=u'Chuck Paluhniuk')>])
>>> session.commit()
>>> session.new
IdentitySet([])
>>> session.identity_map.items()
[((<class 'models.Author'>, (1,)), <Author(name=u'Chuck Paluhniuk')>)]
>>> session.dirty
IdentitySet([])

对象必须以另一种方式进入会话。也许您可以发布一些显示该问题的代码?

更新:我将session.dirty 的输出添加到我的示例代码中。如您所见,它是空的。我不理解反对票。声称load() 更改了会话,但事实并非如此。其他一些代码可以。您能否提供一个显示您的场景的代码示例?

【讨论】:

  • 你可能想检查session.dirty,你会在那里看到对象。您也可以只更改一些属性而不将对象添加到会话执行session.commit(),您会看到它将被刷新到数据库
  • @mehdy 是的,mehdy 是一种仪式。我的代码示例将更等同于文档中的示例。我不希望 schema.load() 将数据加载到 DB Session 中。我在 mehdy 的回答 cmets 中提到了原因。请为此添加您的建议
猜你喜欢
  • 1970-01-01
  • 2017-02-02
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 2018-09-08
  • 2016-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多