自引用SQLAlchemy模型的factoryboy属性错误



我意识到以前也提出过类似的问题(https://github.com/FactoryBoy/factory_boy/issues/173)但我已经尝试了该票证中的所有建议,但在创建SQLAlchemy模型中的自引用字段时仍然存在问题。

具体来说,当我尝试在测试中使用以下格式(如票证中所建议的(创建ScaleFactory对象时:

new_scale = factories.ScaleFactory(code=test_code, description_student=test_description_student, parent_scale__parent_scale=None)

我得到以下错误:

obj = None, name = 'id', default = <class 'factory.declarations._UNSPECIFIED'> . 
def deepgetattr(obj, name, default=_UNSPECIFIED):
"""Try to retrieve the given attribute of an object, digging on '.'.
This is an extended getattr, digging deeper if '.' is found.
Args:
obj (object): the object of which an attribute should be read
name (str): the name of an attribute to look up.
default (object): the default value to use if the attribute wasn't found
Returns:
the attribute pointed to by 'name', splitting on '.'.
Raises:
AttributeError: if obj has no 'name' attribute.
"""
try:
if '.' in name:
attr, subname = name.split('.', 1)
return deepgetattr(getattr(obj, attr), subname, default)
else:
return getattr(obj, name)
E           AttributeError: 'NoneType' object has no attribute 'id'

我的工厂型号是:

class ScaleFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = models.Scale
sqlalchemy_session = models.orm.session
id = lazy_attribute(lambda o: fake.uuid4())
...
parent_scale_id = factory.SelfAttribute("parent_scale.id")
parent_scale = factory.SubFactory('application.factories.ScaleFactory')

我的型号是:

class Scale(orm.Model):
__tablename__ = "scale"
id = orm.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
...
parent_scale_id = orm.Column(UUID(as_uuid=True), orm.ForeignKey("scale.id"))
parent_scale = orm.relationship("Scale", remote_side=[id])

我还尝试了关于该支持票证的所有其他建议(@factory.post_generation等(,但所有建议都导致了无限递归。唯一不会产生无限递归的调用是我在这里给出的调用,但它会导致您看到的AttributeError。很可能我只是不明白我应该在这里传递什么,而不是"无"作为parent_scale_parent_scale。我也尝试过创建一个MagicMock对象,并将其作为parent_scale传递,但在尝试查找__name__时产生了AttributeError。所以我完全被卡住了!我们非常感谢您的帮助。

我在工厂男孩===2.12.0

要回答我自己的问题,以防它对任何人都有帮助,一种防止无限递归和AttributeError的方法是按照原始答案中的建议传递None值(https://github.com/FactoryBoy/factory_boy/issues/173)而且还实现了CCD_ 3挂钩来设置parent_scale_id:

class ScaleFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = models.Scale
sqlalchemy_session = models.orm.session
id = lazy_attribute(lambda o: fake.uuid4())
...
parent_scale = factory.SubFactory("application.factories.ScaleFactory")
@factory.post_generation
def parent_scale_id(self, create, _, **__):
self.parent_scale_id = self.parent_scale.id if self.parent_scale else None

这样说吧:

new_scale = factories.ScaleFactory(code=test_code, description_student=test_description_student, parent_scale__parent_scale__parent_scale__parent_scale=None)                             

这将为您提供一个具有3个父"比例"的"比例"。

最新更新