Python / Django перебирает один список, проверяя внутри Object - PullRequest
3 голосов
/ 25 мая 2011

Каким будет самый чистый путь к следующему псевдокоду?

class Player
   id
   name

class Participant  (is a subset of Player with an added status)
   player_id (ForeignKey to Player)
   status

Так что вы можете иметь список игроков (Уэйн, Чак, Бобби) А затем список участников (Уэйн (статус: ДА), Бобби (статус: НЕТ)) Обратите внимание, что Чака нет в списке участников.

Итак, я перебираю всех игроков и выводю статус, если участники существуют.

player_list = list with Player objects
participant_list = list with Participant objects

for player in player_list:
   if player.id exists in participant_list //QUESTION IS HERE: HOW DO I DO THIS???
         print participant.status

Я не уверен, как проверить внутренний идентификатор списка, который содержит объекты ???

Ответы [ 5 ]

3 голосов
/ 25 мая 2011

добавить в другой цикл

player_list = list with Player objects
participant_list = list with Participant objects

for player in player_list:
    for participant in participant_list:
        if player == participant.player:
            print participant.status
            break

Не самое красивое решение, но простое.

2 голосов
/ 25 мая 2011

Для небольших групп игроков / участников достаточно подстановки поиска:

player_list = Player.objects.all()

# Get all relevant participants (or just all if you like)
player_ids = player_list.value_list('id', flat=True)
participant_list = Participant.objects.filter(player_id__in=player_ids)

# Create a lookup dict
participants = dict([(p.player_id, p) for p in participant_list])

# Everything is now prepared for quick access
for player in player_list:
    if player.id in participants:
        print participants[player.id].status

Если вам приходится делать это часто, возможно, вы захотите использовать другой подход.Вот три варианта:

Наследование

Использование наследования и сохранение статуса в базе данных.Это сделало бы подобные запросы в будущем намного проще / эффективнее:

class Player(models.Model):
    name = models.CharField(max_length=128)
    is_participant = models.BooleanField(default=False)

class Participant(Player):
    status = models.CharField(max_length=32)

    def save(self, *args, **kwargs):
        if not self.id:
            self.is_participant = True
        super(Participant, self).save(*args, **kwargs)

Если ваши данные структурированы таким образом, это означает, что объекты Participant всегда имеют те же поля, что и объекты Player, и вы можете проверитьесли игрок является участником, не обращаясь к базе данных или не просматривая все участники.Однако выбор соответствующего участника приведет к попаданию.Разновидностью этого подхода может быть добавление общего внешнего ключа к Player.Проверка атрибута для None покажет вам, является ли игрок участником, и, перейдя по ссылке, вы перейдете к соответствующему объекту базы данных.

Денормализация

Если статус - это единственное значение, которое вам нужно, вы также можете сохранить его на модели плеера и автоматически синхронизировать его со значением Participant.если вы используете наследование, как указано выше, вы получите его бесплатно:

class Player(models.Model):
    name = models.CharField(max_length=128)
    participant_status = models.CharField(max_length=32)

class Participant(Player):
    pass

Вы можете запросить его следующим образом:

for player in Player.objects.all()
    if player.participant_status:
         print participant.status

Один недостаток заключается в том, что вам придется скрыватьПоле статуса из форм игрока.Но выгода в том, что вы сможете запрашивать: а) если игрок является участником и б) получить статус, не попав в базу данных.

Но этот дизайн, конечно, не так чист, как нормализованная база данных, иэто действительно должно быть сделано, только если цена слишком велика.

Отношение один к одному

Последний подход заключается в использовании OneToOneField, если это однок одному отношению.Теоретически вы можете связать две модели с любой стороны, но я не уверен, как это работает с select_related(), что вы и хотите использовать, чтобы избежать попадания в базу данных более одного раза в списках.

class Player(models.Model):
    name = models.CharField(max_length=128)
    participant = models.OneToOneField('Participant', null=True)

class Participant(models.Model):
    status = models.CharField(max_length=32)

Вы запрашиваете это так:

player_list = Player.objects.all().select_related('participant')

for player in player_list:
   if player.participant_id is not None:
     print player.participant.status
2 голосов
/ 25 мая 2011

То, что вы хотите, это метод values_list() для QuerySet объектов.

player_list = Player.objects.filter(...)
participant_list = Participant.objects.filter(...)
participant_player_id_list = participant_list.values_list('player_id', flat=True)

for player in player_list:
    if player.id in participant_player_id_list:
        print participant_list.get(player_id=player.id).status
0 голосов
/ 26 мая 2011

В том же ключе, что и ответы Джеймса и John2x, вы можете собрать вместе три интересных функции python / django, чтобы сделать это более явным и, возможно, намного быстрее.Методы менеджера values_list и in_bulk могут использоваться для создания словаря объектов модели, в котором атрибут id каждого объекта сопоставляется с полным объектом.Третий прием - это функция словарей Python, которую можно передать непосредственно во встроенную функцию set для получения набора из ключей словаря.Вот так:

import operator

# Get a bulk dict of player objects.
pl_objs = Player.objects
bulk_players = pl_objs.in_bulk(pl_obj.values_list("id", flat=True))

# Get a bulk dict mapping player.id to Participant instances.
bulk_participants = dict((operator.attrgetter("player_id"), x) 
                          for x in Participant.objects.all())

# Now find the overlap with a set intersection; print status.
for _id in set(bulk_players) & set(bulk_participants):
    print bulk_participants[_id].status
0 голосов
/ 25 мая 2011

или я думаю, что вы также можете сделать:

player_list = list with Player objects
participant_list = list with Participant objects

for player, participant in zip(player_list, participant_list):
    if player == participant.player:
            print participant.status
            break

но player_list и participant_list должны иметь одинаковую длину

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...