FactoryBoy: How do I define a factory field for a generic foreign key?

Viewed 226

Since the type of a generic foreign key object is not know until a record is created in the model, what sub factory do I define it as ? Or is there another way to approach this ?

models.py

class Contract(models.Model):
    offer_type = models.ForeignKey(ContentType, on_delete=models.PROTECT)
    offer_id = models.PositiveIntegerField()
    offer = GenericForeignKey('offer_type', 'offer_id')
    invoice = models.ForeignKey('Invoice', on_delete=models.PROTECT)
    status = models.CharField(max_length=8)
    commission = models.DecimalField(max_digits=100, decimal_places=2)

factories.py

class ContractFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.Contract

    #What to do here ???
    offer = factory.SubFactory(????)
    invoice = factory.SubFactory(InvoiceFactory)
    status = 'active'
    commission = 40.00



1 Answers

Somehow you have to pass what kind of model you're willing to see (if not random)

so your proposal is good for one choice, but for a more generic approach use this:

class BaseContractFactory(dj_factory.DjangoModelFactory):
    class Meta:
        model = Contract
        exclude = ['offer']

    offer_id = factory.SelfAttribute('offer.id')
    offer_type = factory.LazyAttribute(
        lambda obj: ContentType.objects.get_for_model(obj.offer)
    )
    ...


class Concrete1ContractFactory(BaseContractFactory):
    offer = factory.SubFactory(Concrete1Factory)


class Concrete2ContractFactory(BaseContractFactory):
    offer = factory.SubFactory(Concrete2Factory)

where Concrete1 and Concrete2 are some existing Django models

Related