Python / Django迭代一个列表,同时检查Object内部

时间:2011-05-25 03:59:49

标签: python django

以下伪代码最干净的方法是什么?

class Player
   id
   name

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

所以你可以有一个球员名单(Wayne,Chuck,Bobby) 然后是参与者名单(Wayne(状态:是),Bobby(状态:NO)) 请注意,Chuck不在参与者列表中。

所以,我正在迭代所有玩家,并在参与者存在的情况下输出状态。

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

我不知道如何检查包含Objects ???

的列表的内部id

5 个答案:

答案 0 :(得分:3)

添加另一个循环

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

不是最漂亮的解决方案,但很简单。

答案 1 :(得分:2)

您想要的是QuerySet对象的values_list()方法。

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

答案 2 :(得分:2)

对于较小的玩家/参与者,查找词典就足够了:

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的属性会告诉您玩家是否也是参与者,然后按照链接将您带到相关的数据库对象。

<强> Denormalisation

如果状态是您需要的唯一值,您也可以将其存储在播放器型号上,并自动将其与您的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

一个缺点是您必须隐藏播放器表单中的状态字段。但好处是,您将能够查询a)如果玩家是参与者并且b)获得状态而不是访问数据库。

但是这种设计肯定不像标准化数据库那么干净,只有在成本太高的情况下才能真正做到。

一对一关系

如果这是一对一关系,最后一种方法是使用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

答案 3 :(得分:0)

与James和John2x的答案一样,你可以将三个有趣的python / django功能组合在一起,以更明确的方式执行此操作,并且可能更快。管理器方法values_listin_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

答案 4 :(得分:-1)

或者我认为你也可以这样做:

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_listparticipant_list必须具有相同的长度