Search code examples
pythondjangofixturesfactory-boy

Django Factory Boy iterate over related parent


I have a project with Clients, Draftschedules, LineItems and Servers.

  • Each client has a single DraftSchedule, each Draftschedule has many Lineitems

  • Each Client has many Servers

  • Each LineItem has a Single Server

enter image description here

I have some code to generate LineItems for each DraftSchedule with random data. However the resulting LineItems contain Servers not actually owned by the Draftschedule Client

class LineItemFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = LineItem

    line_item_type = factory.Iterator(LineItemType.objects.all())
    draftschedule = factory.Iterator(DraftSchedule.objects.all())

    servers = factory.Iterator(Server.objects.all())  # <----- Problem line

    cost = factory.LazyAttribute(lambda x: faker.pydecimal(2, 2, positive=True))
    detail = factory.LazyAttribute(lambda x: faker.sentence())
    ...

I'd like to restrict the server choice set to be only those servers owned by the parent client of the Draftschedule the Lineitem is being created for.

So that when I call LineItemFactory() it returns a new LineItem object and I can garantee that the Server on the LineItem is actually owned by the Client associated with the DraftSchedule

I've tried the following:

servers = factory.Iterator(lambda x: x.draftschedule.client.servers.all())

where client.servers is the related name, but the function isn't iterable so I'm a bit stuck

Is this possible or should I approach the problem from a different angle?


Solution

  • You could try using a lazy_attribute_sequence :

    @factory.lazy_attribute_sequence
    def servers(obj, seq):
        all_servers = obj.draftschedule.client.servers.all()
        nb_servers = all_servers.count()
        return all_servers[seq % nb_servers]