我使用SQLalchemy作为我的ORM,并尝试将我的测试装置移植到factory_boy。我的架构包括一对多关系中的两个对象。即一个模型的实例具有类似于具有另一个模型的实例的列表。例如:
class Person(...):
id = Column(Integer, primary_key=True)
name = Column(Text)
[...]
class Address(...):
id = Column(Integer, primary_key=True)
city = Column(Text)
[...]
person_id = Column(Integer, ForeignKey('person.id'))
person = relationship("Person", backref="addresses")
现在我正在尝试创建一个可以创建具有多个地址的人的工厂。 Factory_boy有{{1}}。但我只看到你如何在一对一的关系中使用它。我知道我可以用一个单独的工厂创建地址然后附加它们,但我想做一些像SubFactory
PersonFactory.create(num_addresses = 4)`。
有没有人知道这是否可以在factory_boy中使用?
我使用factory_boy 2.4.1。
答案 0 :(得分:0)
我有这个确切的问题,并对这里缺乏好的答案感到失望。事实证明这是可能的!将此留给那些有同样问题的人。
首先,你的模型需要在ForeignKey上定义相反模型的关系,所以看起来应该是这样的:
class Person(...):
id = Column(Integer, primary_key=True)
name = Column(Text)
addresses = relationship("Person", backref="person")
[...]
class Address(...):
id = Column(Integer, primary_key=True)
city = Column(Text)
[...]
person_id = Column(Integer, ForeignKey('person.id'))
然后,在你的PersonFactory上,你可以像这样添加一个post_generation钩子:
class PersonFactory(BaseFactory):
[...attributes...]
@factory.post_generation
def addresses(self, create, extracted, **kwargs):
return AddressFactory.create_batch(4)
并替换' 4'无论你想要什么号码。显然,您还需要定义AddressFactory。
答案 1 :(得分:0)
目前,无法实现“多对一RelatedFactory
”,以便“烘焙到您的工厂”......
也就是说,在实例化PersonFactory
时,这种行为可以实施,并且有点hackery。
以下食谱将为您提供所需的信息:
from sqlalchemy import create_engine, Integer, Text, ForeignKey, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, scoped_session, sessionmaker
import factory
from factory.alchemy import SQLAlchemyModelFactory as sqla_factory
import random
engine = create_engine("sqlite:////tmp/factory_boy.sql")
session = scoped_session(sessionmaker(bind=engine))
Base = declarative_base()
class Person(Base):
id = Column(Integer, primary_key=True)
name = Column(Text)
addresses = relationship("Address", backref="person")
class Address(Base):
id = Column(Integer, primary_key=True)
street = Column(Text)
street_number = Column(Integer)
person_id = Column(Integer, ForeignKey('person.id'))
class AddressFactory(sqla_factory):
class Meta:
model = Address
sqlalchemy_session = session
street_number = random.randint(0, 10000)
street = "Commonwealth Ave"
class PersonFactory(sqla_factory):
class Meta:
model = Person
sqlalchemy_session = session
name = "John Doe"
Base.metadata.create_all(engine)
for i in range(100):
person = PersonFactory(addresses=AddressFactory.create_batch(3))
答案 2 :(得分:0)
@Kristen指出了正确的方向,但是AdderssFactory与Person没有关系。 在 Django 中,我们可以像这样使用post_generation装饰器。
class PersonFactory(BaseFactory):
@factory.post_generation
def addresses(self, create, extracted, **kwargs):
self addresses_set.add(AddressFactory(person=self))
答案 3 :(得分:0)
我在项目中使用了这种模式。假设您已经有AddressFactory
。
class PersonFactory(factory.alchemy.SQLAlchemyFactory):
class Meta:
model = Person
@factory.post_generation
def addresses(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
assert isinstance(extracted, int)
AddressFactory.create_batch(size=extracted, person_id=self.id, **kwargs)
用法
PersonFactory(addresses=4)
这将创建具有4个Person
的{{1}}
这也可以接受小矮人
Address
这将创建PersonFactory(addresses=2, addresses__city='London')
,其中包含2个Person
字段,其中Address
字段设置为city
以下是博客文章,可能会对https://simpleit.rocks/python/django/setting-up-a-factory-for-one-to-many-relationships-in-factoryboy/
有所帮助答案 4 :(得分:-2)
您可以使用此处描述的解决方案:http://factoryboy.readthedocs.org/en/latest/recipes.html#reverse-dependencies-reverse-foreignkey
基本上,只需在RelatedFactory
上声明一些PersonFactory
:
class PersonFactory(factory.alchemy.SQLAlchemyFactory):
class Meta:
model = Person
address_1 = factory.RelatedFactory(AddressFactory, 'person')
address_2 = factory.RelatedFactory(AddressFactory, 'person')