Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Factory Boy subfactory over 'self'

Does anyone know how to create the factory in factoryboy based on this models.py

class Halte(models.Model):

    koppel_halte1 = models.ForeignKey('self',
                                  related_name='koppel_halteA',
                                  verbose_name="Koppel Halte",
                                  help_text="geef hier een gekoppelde halte aan",
                                  null=True, blank=True)

    koppel_halte2 = models.ForeignKey('self',
                                  related_name='koppel_halteB',
                                  verbose_name="Koppel Halte",
                                  help_text="geef hier een gekoppelde halte aan",
                                  null=True, blank=True)

Notice the 'self'? (And YES this type of relation is necesarry.)

I have tried several things in FactoryBoy (SubFactory, RelatedFactory, SelfAtribute, PostGeneration) but I can't get it to work.

one of the attempts in a factories.py

class HalteFactoryA(factory.DjangoModelFactory):
    class Meta:
        model = models.Halte


class HalteFactoryB(factory.DjangoModelFactory):
    class Meta:
        model = models.Halte


class HalteFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Halte
    # todo: how to do this?? (see models.Halte)
    koppel_halte1 = factory.RelatedFactory(HalteFactoryA)
    koppel_halte2 = factory.RelatedFactory(HalteFactoryB)

Any advice?

Thank you.

like image 929
Sjoerd van Poelgeest Avatar asked Feb 05 '16 15:02

Sjoerd van Poelgeest


People also ask

What is DjangoModelFactory?

DjangoModelFactory is a basic interface from factory_boy that gives "ORM powers" to your factories. It's main feature here is that it provides you with a common "create" and "build" strategies that you can use to generate objects in your tests.

What is factory boy Python?

factory_boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard to maintain fixtures with easy-to-use factories for complex objects.


2 Answers

@bakkal has it mostly right, but an important missing factor is that a target recursion depth must be specified, as stated in this issue: https://github.com/rbarrois/factory_boy/issues/173

# myproj/myapp/factories.py
class MyModelFactory(factory.Factory):
    class Meta:
        model = models.MyModel
    parent = factory.SubFactory('myapp.factories.MyModelFactory')

Then a recursion max depth needs to be added, or you get the infinite depth reached error (as noted by @Sjoerd van Poelgeest in the comments):

m = MyModelFactory(parent__parent__parent__parent=None)

In This case we are allowing a depth of 3 being created, and the last one will have a null parent.

like image 54
Kinetic Stack Avatar answered Sep 21 '22 13:09

Kinetic Stack


Fully qualified model name in the model FK

To make it easier on the tools to introspect your model, instead of 'self', use the fully qualified model name:

koppel_halte1 = models.ForeignKey('yourapp.Halte', ...)
koppel_halte2 = models.ForeignKey('yourapp.Halte', ...)

Notice it's a string 'yourapp.Halte' and not yourapp.Halte.

Fully qualified factory name in the SubFactory

If you insist on using 'self' in the model you can use the fully qualified model name in your SubFactory

# yourapp/factories.py

class HalteFactory(factory.Factory):
    class Meta:
        model = yourapp.Halte

    koppel_halte1 = factory.SubFactory('yourapp.factories.HalteFactory')
    koppel_halte2 = factory.SubFactory('yourapp.factories.HalteFactory')
like image 25
bakkal Avatar answered Sep 22 '22 13:09

bakkal