Factory boy field for self-referential field in django abstract model

40 Views Asked by At
class BaseOrganization(
    OrganizationModelMixin, TimeStampedModel, OrganizationWidgetsMixin
):
    name = models.CharField(max_length=255, verbose_name="Nomlanishi", null=True)
    juridical_address = models.CharField(
        max_length=150, verbose_name="Yuridik manzili", null=True, blank=True
    )
    phone_number = models.CharField(
        max_length=150,
        verbose_name="Telefon raqami",
        null=True,
        blank=True,
        validators=[phone_regex],
    )
    parent = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="%(class)s_children",
        verbose_name="Yuqori tashkilot",
    )


    class Meta:
        abstract = True

class BaseOrganizationFactory(factory.django.DjangoModelFactory):

    """Base organization factory"""
    name = factory.Faker("company")
    juridical_address = factory.Faker("address")
    phone_number = factory.Faker("phone_number")
    parent = factory.SubFactory(
        "myapp.tests.factories.BaseOrganizationFactory",
    )


@pytest.mark.django_db
class TestBaseOrganization:
    @pytest.fixture(autouse=True)
    def setup(self):
        self.base_organization = BaseOrganizationFactory(
            parent=None
        )

if i call BaseOrganizationFactory in setup method it caused RecursionError: maximum recursion depth exceeded while calling a Python object

1

There are 1 best solutions below

4
Vaibhav On

This is because the BaseOrganizationFactory creates a circular reference with a parent field pointing to itself. This creates an infinite recursion during the factory creation process.

Change your factory to avoid creating circular references. One way to do this is by setting the parent field to None or a random value. Change the logic as per your business logic need

class BaseOrganizationFactory(factory.django.DjangoModelFactory):
   """Base organization factory"""
   name = factory.Faker("company")
   juridical_address = factory.Faker("address")
   phone_number = factory.Faker("phone_number")

   # Using factory.LazyAttribute to avoid circular reference
   parent = factory.SubFactory("myapp.tests.factories.BaseOrganizationFactory")


   class Meta:
        model = BaseOrganization

@pytest.mark.django_db
class TestBaseOrganization:
    @pytest.fixture
    def base_organization(self):
        return BaseOrganizationFactory(parent=None)

    def test_something(self, base_organization):
        # Your test code here
        assert base_organization is not None