Выведенные атрибуты атрибута LazyAttribute с использованием Factory Boy

#python #django #faker #factory-boy

#python #django #мошенник #factory-boy

Вопрос:

Используя Factory Boy и Faker в проекте Django, я хотел бы создать выведенные атрибуты, то есть метод from Faker возвращает набор значений, которые зависят друг от друга. Эти значения будут использоваться для других атрибутов класса Factory.

Пример: location_on_land метод from faker.providers.geo возвращает кортеж из широты, долготы, названия места, двухбуквенного кода страны и часового пояса (например (‘38.70734’, ‘-77.02303’, ‘ Форт Вашингтон», «США», «Америка /Нью-Йорк»). Все значения зависят друг от друга, поскольку координаты определяют место, страну, часовой пояс и т. Д. Поэтому я не могу использовать отдельные функции для (ленивых) атрибутов, таких как faker.providers.latitude , faker.providers.longitude .

Возможно ли каким-либо образом получить доступ к возвращаемым значениям из атрибута lazy, чтобы использовать их для других выведенных атрибутов? Есть ли лучший способ получить доступ к возвращаемым значениям, location_on_land чтобы использовать их для других зависимых атрибутов, мой фабричный класс выглядит следующим образом:

 # factory_models.py

class OriginFactory(factory.django.DjangoModelFactory):
    """Factory for Origin."""

    class Meta:
        model = models.Origin
        exclude = [
            "geo_data",
        ]
    
    # not working since not a lazy attribute
    # lat, lon, place, iso_3166_alpha_2, _ = fake.location_on_land()

    # desired outcome (not working)
    geo_data = factory.Faker("location_on_land")

    # attributes using the return values of `location_on_land` from lazy attribute (pseudo-code, desired)
    latitude = geo_data[...][0]
    longitude = geo_data[...][1]
    # foreign key
    iso_3166_alpha_2 = models.Country.objects.get(iso_3166_alpha_2=geo_data[...][2])
    ...
  
 # models.py

class Origin(models.Model):
    origin_id = models.AutoField(
        primary_key=True,
        db_column="origin_id",
    )

    latitude = models.FloatField(
        null=True,
        db_column="latitude",
    )

    longitude = models.FloatField(
        null=True,
        db_column="longitude",
    )

    region = models.CharField(
        max_length=100,
        blank=True,
        db_column="region",
    )

    iso_3166_alpha_2 = models.ForeignKey(
        to=Country,
        on_delete=models.PROTECT,
        db_column="iso_3166_alpha_2",
    ...
    )
  

Ответ №1:

При использовании factory.Params результирующий атрибут доступен для первого параметра on factory.LazyAttribute : переданный экземпляр является заглушкой, используемой для построения параметров для фактического вызова модели.

В вашем случае я бы выбрал следующую фабрику.

Обратите внимание, что geo_data поле объявлено как параметр (т.Е. Не передается models.Origin конструктору); но оно по-прежнему доступно для других объявлений на заводе.

 class OriginFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Origin

    class Params:
        geo_data = factory.Faker('location_on_land')

    latitude = factory.LazyAttribute(lambda o: o.geo_data[0])
    longitude = factory.LazyAttribute(lambda o: o.geo_data[1])
    iso_3166_alpha_2 = factory.LazyAttribute(
        lambda o: models.Country.objects.get(iso_3166_alpha_2=o.geo_data[3])
    )
  

Комментарии:

1. Большое вам спасибо, у меня есть часы поиска, чтобы найти решение! Я довольно новичок в Factory Boy, поэтому я вообще не знал об этом Params классе.