Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python/Django迭代一个列表,同时检查对象内部_Python_Django - Fatal编程技术网

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

Python/Django迭代一个列表,同时检查对象内部,python,django,Python,Django,以下伪代码最干净的方法是什么 class Player id name class Participant (is a subset of Player with an added status) player_id (ForeignKey to Player) status 所以你可以有一份球员名单(韦恩、查克、鲍比) 然后是参与者名单(韦恩(状态:是),博比(状态:否)) 请注意,Chuck不在参与者列表中 因此,我迭代所有参与者,如果参与者存在,则输出状态 p

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

class Player
   id
   name

class Participant  (is a subset of Player with an added status)
   player_id (ForeignKey to Player)
   status
所以你可以有一份球员名单(韦恩、查克、鲍比) 然后是参与者名单(韦恩(状态:是),博比(状态:否)) 请注意,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

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

或者我认为你也可以:

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 = 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
如果您必须经常这样做,您可能需要使用不同的方法。这里有三种选择

继承

使用继承和在数据库中存储状态。这将使将来的类似查询更容易/更高效:

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
对象具有相同的字段,并且您可以检查某个玩家是否是参与者,而无需点击数据库或遍历所有参与者。然而,获取相关参与者将招致打击。这种方法的一种变体是将通用外键附加到
播放器
。检查
None
属性将告诉您该玩家是否也是参与者,并通过链接将您带到相关的数据库对象

非规范化

如果状态是您需要的唯一值,您也可以将其存储在播放器模型上,并自动将其与您的
参与者
值同步。如果您按上述方式使用继承,您将免费获得:

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
player_list = Player.objects.all().select_related('participant')

for player in player_list:
   if player.participant_id is not None:
     print player.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)
您可以这样查询:

for player in Player.objects.all()
    if player.participant_status:
         print participant.status
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特性组合在一起,以一种更明确、可能更快的方式完成这项工作。管理器方法和可用于构建模型对象字典,其中每个对象的id属性映射到完整对象。第三个技巧是python字典的一个特性,它可以直接传递给内置函数,从字典的键生成一个集合。像这样:

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

这不能满足OP的要求。它将比较player1和participant1,player2和participant2,以此类推。OP希望将每个玩家与每个参与者进行比较(即,玩家1与参与者1、2和3进行比较,然后玩家2与参与者1、2和3进行比较)。再加上问题的陈述方式,列表很可能有不同的长度。你的回答非常深入,但我认为它没有回答真正的问题,即如何使用对象列表,而不是查询集。他必须改变他做事的方式,在我看来,这是一件好事。查询集比对象列表更容易使用。第一种方法(查找dict)也可以使用列表,只需跳过定义
人员列表
参与者列表
标签的行。参与者列表将对每个玩家迭代一次,SQL查询将对每个玩家/参与者运行一次。这意味着,如果您有100名玩家,您将在参与者列表中迭代100次,并运行多达102个SQL查询。将参与者列表转换为dict,您将始终有1个迭代和2个SQL查询,而不考虑参与者的数量。