Поле "Заводской мальчик" не получает ожидаемого значения

Я использую фабрику для генерации данных для моего приложения django.

Это приложение для теннисных матчей, в котором есть игрок один и два, как показано в классе ниже. Любой из них будет победителем, который будет храниться в поле winner_one.

Я получаю имя третьего игрока в этом поле вместо имени первого или второго игрока. Этот игрок также присутствует в таблице.

Посоветуйте, пожалуйста, как лучше всего это исправить?

class MatchFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Match

    player_one = factory.SubFactory(UserFactory)
    player_two = factory.SubFactory(UserFactory)
    league = factory.Iterator(League.objects.all())
    type = fuzzy.FuzzyChoice(Match.MATCH_CHOICES, getter=lambda c: c[0])
    winner_one = random.choice([player_one, player_two])
    start_date = fuzzy.FuzzyNaiveDateTime(
        datetime.today() + relativedelta(months=1),
        datetime.today() + relativedelta(months=3)
    )
    end_date = start_date

Этот кажется хорошим примером использования крючка для генерации постов от factory_boy.

class MatchFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Match

    player_one = factory.SubFactory(UserFactory)
    player_two = factory.SubFactory(UserFactory)
    league = factory.Iterator(League.objects.all())
    type = fuzzy.FuzzyChoice(Match.MATCH_CHOICES, getter=lambda c: c[0])
    start_date = fuzzy.FuzzyNaiveDateTime(
        datetime.today() + relativedelta(months=1),
        datetime.today() + relativedelta(months=3)
    )
    end_date = start_date

    @factory.post_generation
    def winner_one(self, create, extracted, **kwargs):
        if extracted:
            self.winner_one = extracted
        else:
            self.winner_one = random.choice([self.player_one, self.player_two])

Проблема связана с объявлением random.choice([user_one, user_two]): это объявление выполняется во время импорта модуля, а не во время работы фабрики.

В этот момент оба значения будут factory.SubFactory(UserFactory) - т.е. рецепт для создания нового пользователя. После вызова random.choice() он вернет одно из деклараций; таким образом, ваш код эквивалентен:

class MatchFactory(factory.django.DjangoModelFactory):
  ...
  player_one = factory.SubFactory(UserFactory)
  player_two = factory.SubFactory(UserFactory)
  winner_one = factory.SubFactory(UserFactory)

Каждый раз он выбирает 3 разных пользователей.

Я бы предложил следующий шаблон:

  1. Добавьте "параметр", чтобы решить, какой игрок должен выиграть;
  2. Используйте это значение для выбора нужного атрибута:
class MatchFactory(factory.django.DjangoModelFactory):
  class Meta:
    model = Match

  class Params:
    # Decide who the winner is; that field won't be passed to the `Match` model.
    winner = factory.fuzzy.FuzzyChoice([1, 2])

  player_one = factory.SubFactory(UserFactory)
  player_two = factory.SubFactory(UserFactory)
  winner_one = factory.LazyAttribute(
    lambda o: o.player_one if o.winner == 1 else o.player_two
  )

С помощью этого шаблона вы также можете "выбрать" победителя при вызове фабрики: MatchFactory(player_one=some_player, player_two=some_player, winner=1).

Вернуться на верх