7

当两个或多个模型有一个共同的外键时,我的工厂总是会遇到问题,并且每个模型都应该有相同的外键时创建自己的对象。

为了说明这个问题,这里有一个简化的模型结构:

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)

因此 aRecording具有AudioSubtitles,并且两者都有 aLanguage对于每种语言代码都是唯一的。

这是这种结构的工厂。

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”作为代码,如上面的工厂所示。

但是由于每个工厂都尝试创建自己的语言实例,因此使用recording = RecordingFactory()(我经常这样做)实例化 RecordingFactory 会引发异常:

IntegrityError: UNIQUE constraint failed: recordings_language.code

为了解决它,我可以这样做:

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

但这很冗长。在我的实际项目中,我有更多的联系,所以有时我需要在三到四个地方指定语言,有时是四级深度。相反,我希望能够指定一个默认值,如果它已经存在,则创建或使用它。

解决这个问题的正确方法是什么,如果存在的话?

4

2 回答 2

5

您可以使用该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'))
于 2016-09-06T09:49:03.740 回答
0

可能的解决方案是生成共享外键模型,将其分配给每个子工厂,然后在创建模型之前将其删除。

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

    subtitles = factory.SubFactory(
        SubtitlesFactory,
        language=factory.SelfAttribute('.._language')
    )
    audio = factory.SubFactory(
        AudioFactory,
        language=factory.SelfAttribute('.._language')
    )

    _language = factory.SubFactory(Language)

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        kwargs.pop("_language")
        return super()._create(model_class, *args, **kwargs)
于 2022-01-07T16:19:04.440 回答