Для небольших групп игроков / участников достаточно подстановки поиска:
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