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查询,而不考虑参与者的数量。