Not hide soft-deleted instances while using `get_or_create`

Viewed 301

Let's say you are modifying get_queryset in you manager something like this

class VoteManager(models.Manager):

    def get_queryset(self):

        return super().get_queryset().filter(is_deleted=False)



class Vote(models.Model):

    objects = VoteManager()

This works as expected but the problem when you use something like get_or_create on Vote model it creates an instance even if it is present in the database because we modified the get_queryset() method. Can we not shadow the soft-deleted instance while creating??

2 Answers

You can try override get_or_create method too. Like this:

class VoteQuerySet(models.query.QuerySet):

   def get_or_create(...):
      """Your realization"""


class VoteManager(models.Manager):

   def get_queryset(self):

      return VoteQuerySet(model=self.model, using=self._db, hints=self._hints).filter(is_deleted=False)

get_or_create() is a method from Queryset (check this). One way to solve this problem is create your own queryset class and overwrite this method to not hide the soft-deleted instances.

Another way is create a manager and override all() method adding a flag to return all items from database (even soft-deleted instances), like this:

class VoteManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_deleted=False)

    def all(self, force_all=False):
        if force_all:
            return super().get_queryset()  # queryset with all items
        return self.get_queryset()         # queryset without soft-deleted items

Now you can call get_or_create() and soft-deleted instances will not be hidden.

Vote.objects.all(force_all=True).get_or_create(**data)

Vote.objects.all(force_all=True) returns a queryset with all items from database. You can call methods over this queryset like filter(), get_or_create(), update_or_create() and soft-deleted instances will not be hidden.

Related