Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One-to-many relationships in factory_boy

I use SQLalchemy as my ORM and am trying to port my test fixtures to factory_boy. My schema includes two objects in a one-to-many relation. I.e. instances of one model have list like structures with instances of the other. Example:

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")

Now I am trying to create a factory which creates persons with a couple of addresses. Factory_boy has the SubFactory. But I only see how you can use that in a one-to-one relationship. I know I can create the addresses with a separate factory and then attach them, but I would like to do something like person =PersonFactory.create(num_addresses=4)`.

Does anyone know if this is currently possible in factory_boy?

I use factory_boy 2.4.1.

like image 951
NiklasMM Avatar asked Nov 25 '14 07:11

NiklasMM


2 Answers

I am using this pattern in my project. Assuming you already have 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)

Usage

PersonFactory(addresses=4)

This will create Person with 4 Addresses

Also this can accept kwargs

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

This will create Person with 2 Addresses which have city field set to 'London'

Here is blog post which may help https://simpleit.rocks/python/django/setting-up-a-factory-for-one-to-many-relationships-in-factoryboy/

like image 189
Sardorbek Imomaliev Avatar answered Nov 15 '22 23:11

Sardorbek Imomaliev


@Kristen pointed to the right direction, but AdderssFactory didn't related to Person. In Django we can use post_generation decorator like this.

class PersonFactory(BaseFactory):
    @factory.post_generation
    def addresses(self, create, extracted, **kwargs):
        self.addresses_set.add(AddressFactory(person=self))
like image 23
Daniil Mashkin Avatar answered Nov 15 '22 22:11

Daniil Mashkin