带有通用外键

问题描述

我正在尝试为带有 GFK 的模型编写工厂以进行测试,但我似乎无法使其正常工作。我在文档中提到了 common recipes,但我的模型并不完全匹配,而且我也遇到了错误。这是我的模型

class Artwork(models.Model):
    ...
    region = models.ForeignKey("Region",on_delete=models.SET_NULL,null=True,blank=True)

class Region(models.Model):
    # Could be either BeaconRegion or SpaceRegion
    region_content_type = models.ForeignKey(ContentType,on_delete=models.CASCADE)
    region_object_id = models.PositiveIntegerField()
    region = GenericForeignKey("region_content_type","region_object_id")


class SpaceRegion(models.Model):
    label = models.CharField(max_length=255)
    regions = GenericRelation(
        Region,content_type_field="region_content_type",object_id_field="region_object_id",related_query_name="space_region",)


class BeaconRegion(models.Model):
    label = models.CharField(max_length=255)
    regions = GenericRelation(
        Region,related_query_name="beacon_region",)

本质上,一个 Artwork 可以放在两个 Region 之一中; SpaceRegionBeaconRegion

我为相应的模型创建了以下 Factory

class RegionFactory(factory.django.DjangoModelFactory):
    region_object_id = factory.SelfAttribute("region.id")
    region_content_type = factory.LazyAttribute(
        lambda o: ContentType.objects.get_for_model(o.region)
    )

    class Meta:
        exclude = ["region"]
        abstract = True


class BeaconRegionFactory(RegionFactory):
    label = factory.Faker("sentence",nb_words=2)
    region = factory.SubFactory(RegionFactory)

    class Meta:
        model = Region


class SpaceRegionFactory(RegionFactory):
    label = factory.Faker("sentence",nb_words=2)
    region = factory.SubFactory(RegionFactory)

    class Meta:
        model = Region


class ArtworkFactory(factory.django.DjangoModelFactory):
    ...
    region = factory.SubFactory(SpaceRegionFactory)

在我的测试中,我尝试使用 ArtworkFactory() 创建一个艺术品,但它出错了

AttributeError: The parameter 'region' is unkNown. Evaluated attributes are {},deFinitions are <DeclarationSet: {'region_object_id': <SelfAttribute('region.id',default=<class 'factory.declarations._UNSPECIFIED'>)>,'region_content_type': <factory.declarations.LazyAttribute object at 0x1068cf430>,'label': <factory.faker.Faker object at 0x1068cf880>}>

在这里做错了什么?

解决方法

问题出现在解决 ArtworkFactory.region.region,即 SpaceRegionFactory.region 时。

从您的模型看来:

  • Region 是一个指向 SpaceRegionBeaconRegion
  • 的表
  • SpaceRegionBeaconRegion 是简单的表,具有检索相关 Region 对象的帮助程序。

在那些复杂的关系链中,第一步是编写没有工厂的代码:

>>> shire = SpaceRegion(label="Shire")
>>> shire_generic = Region(region=shire)
>>> the_ring = Artwork(region=shire_generic)

这告诉我们,Region 总是在 SpaceRegionBeaconRegion 之后创建,给出以下工厂:


class SpaceRegionFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.SpaceRegion
    label = factory.Faker("sentence",n_words=2)


class RegionFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Region

    region = factory.SubFactory(SpaceRegionFactory)


class ArtworkFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Artwork

    region = factory.SubFactory(RegionFactory)

有了这个,你应该能够让你的代码工作。 请注意我们如何简单地在 region 上设置 Region 字段:Django 的内部结构将自动提取对象内容类型/内容 ID。

其他选项

您可以调整 RegionFactory 以让来电者决定他们想要 SpaceRegion 还是 BeaconRegion

class RegionFactory(factory.django.DjangoModelFactory):
    class Meta:
        models = Region

    class Params:
        space = True  # Request a SpaceRegion

    region = factory.Maybe(
        factory.SelfAttribute("space"),factory.SubFactory(SpaceRegion),factory.SubFactory(BeaconRegion),)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...