简体   繁体   English

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

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

What would the cleanest way to the following pseudocode be?以下伪代码最干净的方法是什么?

class Player
   id
   name

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

So you can have a list of Players (Wayne, Chuck, Bobby) And then a list of Participants (Wayne(status:YES), Bobby(status:NO)) Notice that Chuck is not inside the participant list.所以你可以有一个玩家列表(Wayne,Chuck,Bobby)然后是参与者列表(Wayne(status:YES),Bobby(status:NO))注意Chuck不在参与者列表中。

So, I am iterating over all the Players, and outputting the status if the Participants exist.因此,我正在遍历所有玩家,并在参与者存在时输出状态。

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

I am not sure how to check the inside id of the list that contains Objects???我不知道如何检查包含对象的列表的内部 id ???

add in another loop添加另一个循环

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

Not the prettiest solution but simple.不是最漂亮的解决方案,但很简单。

What you want is the values_list() method for QuerySet objects.您想要的是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

For smaller sets of players/participants, a lookup dict is enough:对于较小的玩家/参与者集合,查找字典就足够了:

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

If you have to do this often, you might want to use a different approach.如果您必须经常这样做,您可能需要使用不同的方法。 Here are three alternatives.这里有三种选择。

Inheritance Inheritance

Use inheritance and to store the status in the database.使用 inheritance 并将状态存储在数据库中。 This would make similar queries in the future much easier/more efficient:这将使将来的类似查询更容易/更有效:

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)

Having your data structured like this means that Participant objects always have the same fields as Player objects and that you can check if a player is a participant without hitting the database or looping through all the participants.将数据结构化为这样意味着Participant对象始终具有与Player对象相同的字段,并且您可以检查玩家是否是参与者,而无需访问数据库或遍历所有参与者。 Fetching the relevant participant however will incur a hit.然而,获取相关参与者会受到打击。 A variation on this approach would be to attach a generic foreign key to the Player .这种方法的一种变体是将通用外键附加到Player Checking the attribute for None will tell you if the player is a participant too, and following the link will take you to the relevant database object.检查None属性将告诉您玩家是否也是参与者,点击链接将带您进入相关数据库 object。

Denormalisation非规范化

If status is the only value you need, you can store it on the player model too, and automatically synchronise it with your Participant value.如果 status 是您需要的唯一值,您也可以将其存储在播放器 model 上,并自动与您的Participant值同步。 if you use inheritance as above, you'll get it for free:如果您使用上述 inheritance,您将免费获得:

class Player(models.Model):
    name = models.CharField(max_length=128)
    participant_status = models.CharField(max_length=32)

class Participant(Player):
    pass

You can query it like this:您可以像这样查询它:

for player in Player.objects.all()
    if player.participant_status:
         print participant.status

One drawback is that you will have to hide the status field from player forms.一个缺点是您必须对播放器 forms 隐藏状态字段。 But the benefit is that you will be able to query a) if the player is a participant and b) get the status without hitting the database.但好处是您将能够查询 a) 玩家是否是参与者,并且 b) 在不访问数据库的情况下获取状态。

But this design is certainly not as clean as a normalised database, and it should only really be done if the cost is too great.但是这种设计肯定不如规范化的数据库那么干净,只有在成本太高的情况下才应该真正做到。

One to one relation一对一关系

A final approach is to use the OneToOneField if this is a one to one relation.如果这是一对一的关系,最后一种方法是使用OneToOneField Theoretically you can link the two models from either side, but I'm not sure how this works with select_related() , which is what you'll want to use to avoid hitting the database more than once on lists.从理论上讲,您可以从任一侧链接两个模型,但我不确定这如何与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)

You query it like this:你像这样查询它:

player_list = Player.objects.all().select_related('participant')

for player in player_list:
   if player.participant_id is not None:
     print player.participant.status

Along the same lines as the answers by James and John2x, you could roll three interesting python/django features together to do this in a way that is more explicit and probably much faster.与 James 和 John2x 的答案相同,您可以将三个有趣的 python/django 功能组合在一起,以一种更明确且可能更快的方式来完成此操作。 The manager methods values_list and in_bulk can be used to build a dictionary of model objects where each object's id attribute is mapped to the full object.管理器方法values_listin_bulk可用于构建 model 对象的字典,其中每个对象的 id 属性映射到完整的 object。 The third trick is a feature of python dictionaries, which can be passed directly to the built-in function set to produce a set from the dictionary's keys.第三个技巧是 python 字典的一个特性,它可以直接传递给内置的 function集合,以从字典的键生成一个集合。 Like so:像这样:

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

or i think you can also do:或者我认为你也可以这样做:

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

but both player_list and participant_list have to have the same lengthplayer_listparticipant_list列表都必须具有相同的长度

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

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