Django overriding filter() without change existing code logic
I have a table in production that is integrated everywhere in the system, now I need to make add a new column in the table with a default value, but don't want to change all the existing logic, what is the best to do that?
class People(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=20)
class = models.CharField(max_length=20)
in the system, we have this kind of queries everywhere
People.objects.filter(gender='male')
People.objects.filter(gender='female', class="3rd")
...
Now we need to add a new field:
class People(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=20)
class = models.CharField(max_length=20)
graduated = models.BooleanField(default=False)
Assume that all the existing data should have graduated
is False, so all the existing should work if we can add graduated=False
, but is there any way we can do so we don't need to change any of the existing code but they will assume graduated=False
?
Yes, you can make a manager such that .objects
will only retain People
with graduated=False
:
class PeopleManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(graduated=False)
class People(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=20)
class = models.CharField(max_length=20)
graduated = models.BooleanField(default=False)
objects = PeopleManager()
all = models.Manager()
You can use People.all.all()
to retrieve all People
, and People.objects.all()
to retrieve all People
that did not graduate.
That being said, I do not recommend this: often People.objects.all()
gives the impression that one will retrieve all People
. As the Zen of Python says: "explicit over implicit": it is better that the code explains and hints what it is doing, not move filtering somewhere hidden in a manager.