Указать имена столбцов Factory db с помощью FactoryBoy в Django Test?
У меня есть несколько неуправляемых моделей, для которых я пытаюсь разработать некоторые фабрики, чтобы я мог собрать несколько тестов. Проблема в том, что у пары из них есть имена db_column
, и это приводит к ошибке в фабрике.
Мои модели выглядят следующим образом:
class Identity(models.Model):
id = models.IntegerField(db_column="identityID", primary_key=True)
person_id = models.IntegerField(db_column="personID")
birth_date = models.DateField(db_column="birthdate")
gender = models.CharField(db_column="gender", max_length=1)
class Meta(object):
# This is 'True' when testing so it's treated like a normal model
managed = getattr(settings, "UNDER_TEST", False)
db_table = "identity"
class Person(models.Model):
id = models.IntegerField(db_column="personID", primary_key=True)
identity = models.ForeignKey(
Identity, db_column="currentIdentityID", on_delete=models.PROTECT
)
ticket_number = models.IntegerField(db_column="ticketNumber")
class Meta(object):
# This is 'True' when testing so it's treated like a normal model
managed = getattr(settings, "UNDER_TEST", False)
db_table = "person"
class YearTerm(models.Model):
active = models.BooleanField(default=False)
name = models.CharField(max_length=50)
created_by = models.ForeignKey(
Person, on_delete=models.PROTECT
)
class Meta:
# This is 'True' when testing so it's treated like a normal model
managed = getattr(settings, "UNDER_TEST", False)
db_table = "[ALTS].[yearterm]"
Мои фабрики выглядят следующим образом:
class IdentityFactory(factory.django.DjangoModelFactory):
class Meta:
model = Identity
@classmethod
def _setup_next_sequence(cls):
try:
return Identity.objects.latest("id").id + 1
except Identity.DoesNotExist:
return 1
id = factory.Sequence(lambda n: n)
person_id = factory.Sequence(lambda n: n)
birth_date = factory.fuzzy.FuzzyDateTime(timezone.now())
gender = factory.Faker("random_element", elements=[x[0] for x in GENDERS])
class PersonFactory(factory.django.DjangoModelFactory):
class Meta:
model = Person
@classmethod
def _setup_next_sequence(cls):
try:
return Person.objects.latest("id").id + 1
except Person.DoesNotExist:
return 1
id = factory.Sequence(lambda n: n)
identity = factory.RelatedFactory(
IdentityFactory,
person_id=factory.SelfAttribute("..id"),
)
ticket_number = factory.Faker("random_int", min=1000, max=40000)
class YearTermFactory(factory.django.DjangoModelFactory):
class Meta:
model = YearTerm
django_get_or_create = ("name",)
active = Iterator([True, False])
name = FuzzyChoice(["Occasionally", "Sometimes", "Always"])
created_by = SubFactory(PersonFactory)
Мой тестовый пример чрезвычайно прост:
class TestCaseYearTerm(TestCase):
def test_create(self):
"""
Test the creation of a YearTerm model using a factory
"""
year_term = YearTermFactory.create()
self.assertEqual(YearTerm.objects.count(), 1)
Но я получаю следующую ошибку:
django.db.utils.IntegrityError: NOT NULL constraint failed: person.currentIdentityID
Мне кажется, что это происходит потому, что я указываю db_column
имя в модели, но я не уверен, как исправить это в FactoryBoy или заставить factory boy добавлять определенное имя к атрибутам фабрик при их создании.
Любая помощь будет принята с благодарностью!
Модели могут быть улучшены. ОП имеет модели Person
и Identity
и хочет, чтобы одна Person
соответствовала только одной Identity
(как профиль пользователя/персоны). ОП может достичь этого с помощью OneToOneField. Таким образом, можно отредактировать модель Identity OP следующим образом
class Identity(models.Model):
person = models.OneToOneField(Person, on_delete=models.CASCADE)
Обратите внимание, что я не использую person_id
. Использование _id в полях модели Django для OneToOneField и Foreign является анти-паттерном. Также, в модели ОП Person
удалите поле identity, поскольку оно больше не нужно. После этого ОП нужно будет выполнить makemigrations
.
Тогда заводы ОП станут проще
import factory
from factory import SubFactory
from factory.django import DjangoModelFactory
class IdentityFactory(DjangoModelFactory):
person = SubFactory(PersonFactory)
class Meta:
model = Identity
Не забудьте также удалить идентификацию из PersonFactory
.