Как создать фабрики-мальчики для моделей Django с одним и тем же внешним ключом

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

Чтобы проиллюстрировать проблему, вот упрощенная структура модели:

class Language (models.Model):
    code = models.CharField(max_length=3, unique=True)


class Audio(models.Model):
    language = models.ForeignKey(Language)
    soundfile = models.FileField()


class Subtitles(models.Model):
    language = models.ForeignKey(Language)
    text = models.TextField()


class Recording(models.Model):
    audio = models.ForeignKey(Audio)
    subtitles = models.ForeignKey(Subtitles)

Таким образом, у Recording есть Audio и Subtitles, и у обоих есть Language, который уникален для каждого языкового кода.

Вот заводы для этой структуры.

class LanguageFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = Language


class AudioFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = Audio

    language = factory.SubFactory(LanguageFactory, code='en1')


class SubtitlesFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = Subtitles

    language = factory.SubFactory(LanguageFactory, code='en1')


class RecordingFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = Recording

    audio = factory.SubFactory(AudioFactory)
    subtitles = factory.SubFactory(SubtitlesFactory)

Это очень распространенный случай, когда звук и субтитры имеют один и тот же язык, поскольку обычно это просто стенограмма. Поэтому я хочу, чтобы RecordingFactory по умолчанию имела аудио и субтитры с языком «en1» в качестве кода, как это отражено в приведенных выше фабриках.

Но поскольку каждая фабрика пытается создать свой собственный экземпляр языка, создание экземпляра RecordingFactory с помощью recording = RecordingFactory() (что я часто делаю) вызывает исключение:

IntegrityError: UNIQUE constraint failed: recordings_language.code

Чтобы решить эту проблему, я могу сделать что-то вроде этого:

language = LanguageFactory(code='en1')
recording = RecordingFactory(subtitles__language=language, audio__language=language)

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

Каков правильный способ обойти это, если он существует?


person Björn Kristinsson    schedule 06.09.2016    source источник


Ответы (1)


Вы можете использовать параметр Params (http://factoryboy.readthedocs.io/en/latest/reference.html#parameters):

class RecordingFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Recording

    class Params:
        language = factory.SubFactory(Language)

    subtitles = factory.SubFactory(SubtitlesFactory, 
        language=factory.SelfAttribute('language'))
    audio = factory.SubFactory(AudioFactory, 
        language=factory.SelfAttribute('language'))
person Xelnor    schedule 06.09.2016
comment
Спасибо, я не знал, что могу использовать Params вот так. попробую - person Björn Kristinsson; 06.09.2016
comment
Я не могу заставить это работать, получаю следующую ошибку CyclicDefinitionError: Cyclic lazy attribute definition for language; cycle found in ['language']. - person Björn Kristinsson; 06.09.2016
comment
Я столкнулся с аналогичной проблемой. Вы нашли решение? - person silentser; 11.10.2016