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

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

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

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

# 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",
    ...
    )

person AuthenticFood    schedule 18.11.2020    source источник


Ответы (1)


При использовании factory.Params результирующий атрибут доступен с первого параметр в 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])
    )
person Xelnor    schedule 18.11.2020
comment
Большое спасибо, я часами искал решение! Я новичок в Factory Boy, поэтому я вообще не знал о классе Params. - person AuthenticFood; 19.11.2020