12

我使用 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 有SubFactory. 但我只看到你如何在一对一的关系中使用它。我知道我可以使用单独的工厂创建地址,然后附加它们,但我想做一些类似person =PersonFactory.create(num_addresses=4)` 的事情。

有谁知道目前在 factory_boy 中是否可行?

我使用 factory_boy 2.4.1。

4

5 回答 5

9

我在我的项目中使用这种模式。假设您已经拥有AddressFactory.

https://factoryboy.readthedocs.io/en/latest/reference.html?highlight=post_generation#factory.post_generation

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)

这将Person使用 4 个Addresses创建

这也可以接受 kwargs

PersonFactory(addresses=2, addresses__city='London')

这将创建Person2 个字段设置为的Addressescity'London'

这是一篇可能对https://simpleit.rocks/python/django/setting-up-a-factory-for-one-to-many-relationships-in-factoryboy/有所帮助的博文

于 2019-02-08T07:14:10.697 回答
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。

于 2016-06-17T01:59:42.070 回答
0

目前,没有办法实现“多对一RelatedFactory”,使其“烘焙到您的工厂”......

也就是说,在实例化您PersonFactory.

以下食谱将为您提供所需的东西:

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))
于 2017-05-09T16:15:51.933 回答
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))
于 2018-07-03T08:06:57.770 回答
-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')
于 2014-11-25T09:34:37.600 回答