Как я могу издеваться над объектом модели django?

Например, в моем проекте есть много взаимосвязанных таблиц

class A(models.Model):
    name = models.models.CharField(max_length=16)

class B(models.Model):
    name = models.models.CharField(max_length=16)
    a = models.ForeignKey(A, on_delete=models.CASCADE)

class C(models.Model):
    name = models.models.CharField(max_length=16)
    b = models.ForeignKey(B, on_delete=models.CASCADE)

и так далее.

Мне нужно протестировать модель C и меня не интересуют модели A и B. Есть ли возможность сделать макет модели B, который можно использовать при создании объектов модели C? Я имею в виду, что я хотел бы создать несколько объектов без создания массивной тестовой базы для тестирования одной крошечной модели.

Если это только для некоторых тестов и вам нужно только несколько экземпляров, вы можете сделать что-то вроде этого:

model_a_instance = A(name='somename')
model_b_instance = B(name='somename2', a=model_a_instance)
model_c_instance = C(name='somename3', b=model_b_instance)

Тем не менее, если вам нужно сохранить модель_c в БД, убедитесь, что модель_a и модель_b также сохранены.

Если вы собираетесь использовать эти модели более широко, я бы рекомендовал создать класс-фабрику для наполнения ваших моделей.

Надеюсь, это помогло.

вы можете использовать пекарню

from model_bakery import baker
AmodelInstance = baker.make(A)

После нескольких дней исследований у меня нет ответа на мой вопрос, но я думаю, что нашел инструмент, который берет на себя заботу о "подготовке базы" перед фактическим тестированием или значительно упрощает ее.

У меня в проекте около 1000 строк тестового кода, и я решил перейти на pytest и переписать тесты почти с нуля, поэтому я делаю то, чего надеялся избежать, но это приемлемо для меня в данном случае.

Вместо создания объектов queryset через django ORM я использую Factory Boy для определения фабрик, которые разрешают отношения с базой данных так, как я хочу.

Для примера я бы реализовал что-то вроде этого:

import factory

class AFactory(factory.django.DjangoModelFactory):
    
    class Meta:
        model = A

class BFactory(factory.django.DjangoModelFactory):
    
    class Meta:
        model = B

    a = factory.SubFactory(AFactory)

class CFactory(factory.django.DjangoModelFactory):
    
    class Meta:
        model = C

    b = factory.SubFactory(BFactory)

Итак, для тестирования модели C вы просто создаете объект модели C через CFactory.create(), а все "цепочки" обрабатываются с помощью SubFactories.

Однако, модели примеров не имеют никаких ограничений, в отличие от реальных таблиц базы данных. Приведем пример для более наглядного ответа:

class Country(models.Model):
    name = models.CharField(choices=(('BY', 'Belarus'), ('UA', 'Ukraine')),
                            max_length=64, unique=True)

class Employee(models.Model):
    name = models.CharField(max_length=64)
    email = models.EmailField(max_length=100, unique=True)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)

class Supervisor(models.Model):
    name = models.CharField(max_length=64)
    email = models.EmailField(max_length=100, unique=True)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE)

Если бы я использовал тот же подход, что и в примере A B C и выполнил что-то вроде SupervisorFactory.create(), то как минимум 2 раза нарушил бы ограничения Country.name и Employee.email. 2 вызова SupervisorFactory попытались бы создать 4 страны, но возможно создать только 3 - 'BY', 'UA', и пустую строку, которая по умолчанию используется фабрикантом. Таким образом, необходимо указать правила, по которым фабрики генерируют данные:

class CountryFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = Country
        django_get_or_create = ('name',)

    name = factory.Iterator('BY', 'UA')

class EmployeeFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = Employee

    email = factory.Sequence(lambda nums: 'employee.%04d@employee.io' % nums)
    country = factory.SubFactory(CountryFactory)

class Supervisor(factory.django.DjangoModelFactory):

    class Meta:
        model = Supervisor

    email = factory.Sequence(lambda nums: 'supervisor.%04d@supervisor.io' % nums)
    country = factory.SubFactory(CountryFactory)
    employee = factory.SubFactory(EmployeeFactory)

Надеюсь, это сэкономит ваше время.

Вернуться на верх