Использование Factory Boy внутри dict для фабрики моделей данных в Django? В качестве альтернативы, заставить FactoryBoy оценивать субфакторию по требованию?

#django #factory-boy

#django #factory-boy

Вопрос:

У меня есть следующий ModelFactory:

 class ProjectDataModelFactory(DjangoModelFactory):
    project = factory.SubFactory("projects.factories.ProjectModelFactory")
    version = "1"
    content = {
        "id": {"value": fuzzy.FuzzyText(length=7, chars=string.ascii_letters).fuzz().upper(), "type": "string"},
        "win_probability": {"value": fuzzy.FuzzyInteger(0, 100).fuzz(), "type": "number"},
        "bid_value": {
            "value": fuzzy.FuzzyInteger(0, 10000000).fuzz(),
            "type": "number",
        },
        "status": {"value": random.choice(["Won", "Lost"]), "type": "string"},
        "sector": {
            "value": random.choice(
                ["Construction", "Technology", "Finance", "Consulting", "Agriculture", "Engineering"]
            ),
            "type": "string",
        },
    } 
  

В content["id"] , я хотел бы иметь value be project.external_id вместо fuzzy.FuzzyText(length=7, chars=string.ascii_letters).fuzz().upper(). external_id is часть ProjectModel. , но когда я ставлю project.external_id вместо fuzzer, я получаю эту ошибку:

AttributeError: объект ‘SubFactory’ не имеет атрибута ‘external_id

Это только кажется проблемой с dicts. У нас не было проблем с его использованием в других контекстах.

У меня нет большого опыта использования FactoryBoy, поэтому это может быть что-то тривиальное. Есть идеи?

Ответ №1:

У вас есть первая проблема: все вызовы random or .fuzz() , которые вы вводите в content dict, оцениваются при импорте класса: каждый экземпляр будет использовать одни и те же значения.

Чтобы выполнить отложенную оценку, вы ДОЛЖНЫ обернуть их в some factory_boy -provided объявление:

 class ProjectDataModelFactory(DjangoModelFactory):
    project = factory.SubFactory("projects.factories.ProjectModelFactory")
    version = "1"
    content = factory.Dict(
        id=factory.Dict(
            value=fuzzy.FuzzyText(length=7, chars=string.ascii_uppercase),
            type="string",
        ),
        win_probability=factory.Dict(
            value=fuzzy.FuzzyInteger(0, 100),
            type="number",
        ),
        bid_value=factory.Dict(
            value=fuzzy.FuzzyInteger(0, 10_000_000),
            type="number",
        ),
        status=factory.Dict(
            value=fuzzy.FuzzyChoice(["Won", "Lost"]),
            type="string",
        ),
        sector=factory.Dict(
            value=fuzzy.FuzzyChoice(
                ["Construction", "Technology", "Finance", "Consulting", "Agriculture", "Engineering"],
            ),
            type="string",
        ),
    )
  

factory.Dict(**kwargs) по сути, это псевдоним для factory.SubFactory(DictFactory, **kwargs) ; затем вы можете использовать любое объявление, как если бы использовали simple SubFactory .

Для вашей первоначальной цели теперь вы сможете легко использовать все функции:

 class ProjectDataModelFactory(DjangoModelFactory):
    project = factory.SubFactory("projects.factories.ProjectModelFactory")
    version = "1"
    content = factory.Dict(
        id=factory.Dict(
            # . is the {"value": x, "type": "string"} dict;
            # .. is {"id": {"value": x, ...}} dict;
            # ... is the ProjectData(content={"id": {...}}) object.
            value=factory.SelfAttribute('...project.external_id'),
            type="string",
        ),
        # Other fields here
    )