django - use method on every object in queryset like filter '__in' custom manager

2.7k Views Asked by At

Hello I would like to implement method for player to take list of players (query set) and leave clan

I'm looking for something like:

Player.leave_clan([1,2,3])
Player.leave_clan([p1,p2,p3])

What I have tried is the method which takes list of account_ids [1,2,3] and then I use updated method on query, but here I have to pass only account IDs

def remove_leavers(self, leavers, clan):
    players = Player.objects.filter(account_id__in=leavers)
    players.update(clan=None,
                   previous_clan=clan)

and with my current models I could call something like:

leavers = Player.objects.filter(account_id__in=[1,2,3]
for player in leavers:
    player.leave_clan()

But I do not think it's right way to do. I use following models down bellow, thank you for all suggestion and recommendations. I think I need custom manager but I did not know how to write it even after reading the documentation.

from django.db import models
class Clan(models.Model):
    clan_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=100)
    tag = models.CharField(max_length=5)

    def __str__(self):
        return "{tag}".format(tag=self.tag)

    @property
    def members(self):
        return Player.objects.filter(clan=self)

    def kick_player(self, player):
        player.leave_clan()

class Player(models.Model):
    account_id = models.IntegerField(primary_key=True)
    account_name = models.CharField(max_length=250)


    clan = models.ForeignKey('Clan',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True,
                            related_name='current_clan')

    previous_clan = models.ForeignKey('Clan',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True,
                            related_name='previous_clan')


    def __str__(self):
        return '{0} - {1}'.format(self.account_name, self.account_id)

    def leave_clan(self):
        self.previous_clan = self.clan
        self.clan = None
        self.save()
1

There are 1 best solutions below

1
On BEST ANSWER

If you want to use a Manager you can do this :

class PlayerManager(models.Manager):
    def leave_clan(self, players):
        """
        Take a list of player. And removed them from their clan
        """
        for player in players:
            player.leave_clan()


class Player(models.Model):
    account_id = models.IntegerField(primary_key=True)
    account_name = models.CharField(max_length=250)


    clan = models.ForeignKey('Clan',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True,
                            related_name='current_clan')

    previous_clan = models.ForeignKey('Clan',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True,
                            related_name='previous_clan')


    def __str__(self):
        return '{0} - {1}'.format(self.account_name, self.account_id)

    def leave_clan(self):
        self.previous_clan = self.clan
        self.clan = None
        self.save()

How to use it

Player.objects.leave_clan(LIST_PLAYERS)

Hope it helps you.