[英]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_list和in_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_list
和participant_list
列表都必须具有相同的长度
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.