1

I'm using a custom Model-Manager for Soft-Deletion and want to do a reverse Foreignkey lookup (Related Manager).

The Manager:

class SoftDeletionQuerySet(QuerySet):
    def delete(self):
        return super(SoftDeletionQuerySet, self).update(deleted_at=timezone.now())

    def hard_delete(self):
        return super(SoftDeletionQuerySet, self).delete()

    def alive(self):
        return self.filter(deleted_at=None)

    def dead(self):
        return self.exclude(deleted_at=None)


class SoftDeletionManager(models.Manager):
    use_for_related_fields = True

    def __init__(self, *args, **kwargs):
        self.status = kwargs.pop("status", "all")
        super(SoftDeletionManager, self).__init__(*args, **kwargs)

    def get_queryset(self):
        if self.status == "alive":
            return SoftDeletionQuerySet(self.model).filter(deleted_at=None)
        elif self.status == "dead":
            return SoftDeletionQuerySet(self.model).exclude(deleted_at=None)
        else:
            return SoftDeletionQuerySet(self.model)

    def hard_delete(self):
        return self.get_queryset().hard_delete()



class SoftDeletionModel(models.Model):
    deleted_at = models.DateTimeField(blank=True, null=True)

    objects = SoftDeletionManager(status="alive")
    dead_objects = SoftDeletionManager(status="dead")
    all_objects = SoftDeletionManager()

    class Meta:
        abstract = True

    def delete(self):
        self.deleted_at = timezone.now()
        self.save()

    def hard_delete(self):
        super(SoftDeletionModel, self).delete()

Used for a Model:

class Sowi(SoftDeletionModel):
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

Now, for a given user, i want to get his user.sowi_set, but only those SoWi's which are 'alive'. The "normal" user.sowi_set also returns the Elements which are dead, i.e. which have a deleted_at value != None. How do I only get the alive objects?

Thanks in Advance!

Sarius
  • 125
  • 2
  • 16

1 Answers1

0

When user.sowi_set.all() called, your manager will initialize by django automatically with empty parameter. To solve this problem, I looked for ways to pass parameters when django initializes manager. Then, I found this question.

You must change code like this.

def manager_factory(status=None):
    class SoftDeletionManager(models.Manager):
        deletion_status = status
        use_for_related_fields = True

        def get_queryset(self):
            if self.deletion_status == "alive":
                return SoftDeletionQuerySet(self.model).filter(deleted_at=None)
            elif self.deletion_status == "dead":
                return SoftDeletionQuerySet(self.model).exclude(deleted_at=None)
            else:
                return SoftDeletionQuerySet(self.model)

        def hard_delete(self):
            return self.get_queryset().hard_delete()
    return SoftDeletionManager()


class SoftDeletionModel(models.Model):
    deleted_at = models.DateTimeField(blank=True, null=True)

    objects = manager_factory("alive")
    dead_objects = manager_factory("dead")
    all_objects = manager_factory()

    class Meta:
        abstract = True

    def delete(self):
        self.deleted_at = timezone.now()
        self.save()

    def hard_delete(self):
        super(SoftDeletionModel, self).delete()

Jrog
  • 1,469
  • 10
  • 29