繁体   English   中英

Python/Django 遍历一个列表,同时检查 Object

[英]Python/Django iterating over one list, while checking inside Object

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

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(status:YES),Bobby(status: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

我不知道如何检查包含对象的列表的内部 id ???

添加另一个循环

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

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

您想要的是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

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

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

如果您必须经常这样做,您可能需要使用不同的方法。 这里有三种选择。

Inheritance

使用 inheritance 并将状态存储在数据库中。 这将使将来的类似查询更容易/更有效:

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属性将告诉您玩家是否也是参与者,点击链接将带您进入相关数据库 object。

非规范化

如果 status 是您需要的唯一值,您也可以将其存储在播放器 model 上,并自动与您的Participant值同步。 如果您使用上述 inheritance,您将免费获得:

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

一个缺点是您必须对播放器 forms 隐藏状态字段。 但好处是您将能够查询 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

与 James 和 John2x 的答案相同,您可以将三个有趣的 python/django 功能组合在一起,以一种更明确且可能更快的方式来完成此操作。 管理器方法values_listin_bulk可用于构建 model 对象的字典,其中每个对象的 id 属性映射到完整的 object。 第三个技巧是 python 字典的一个特性,它可以直接传递给内置的 function集合,以从字典的键生成一个集合。 像这样:

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM