Question

I see in the Django documentation :

Model Instance reference : Creating objects

You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved.
Rather than overriding __init__, try using one of these approaches:

  • Add a classmethod on the model class.
  • Add a method on a custom manager (usually preferred)

Why is the second solution "usually preferred" ?

In a situation where I have a model B which extends a model A through a OneToOne relation, and I want to create a method generating a B object which generates the corresponding A object as well, how is it "better" to use a custom manager as suggested, given I'll probably not use this manager for anything other than what is provided by default manager ?

Was it helpful?

Solution

I think it is preferred because it looks cleaner in code. You might also be reading into the emphasizes a bit too much, as the benefit or difference isn't that big. That said, when implementing things myself I do use the proposed approach.

Consider the following model (purely for illustrative purposes):

class Vehicle(models.Model):
    wheels = models.IntegerField()
    color = models.CharField(max_length=100)

In your application, the need often arises to get all cars, or all motorcycles, or whatever type of vehicle. To keep things DRY, you want some standard form of retrieving this data. By using class methods, you'd get the following:

class Vehicle(models.Model):
    #(...)
    @classmethod
    def cars(cls):
        return Vehicle.objects.filter(wheels=4)

cars = Vehicle.cars()
green_cars = Vehicle.cars().filter(color='green')

If you create a manager, you'll get something like this:

class CarManager(models.Manager):
    def get_query_set(self):
        return super(CarManager, self).get_query_set().filter(wheels=4)

class Vehicle(models.Model):
    #(...)
    car_objects = CarManager()

cars = Vehicle.car_objects.all()
green_cars = Vehicle.car_objects.filter(color='green')

In my opinion, the latter looks cleaner, especially when things get more complex. It keeps the clutter out of your model definitions, and keeps things similar to using the default objects manager.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top