vendredi 17 février 2017

Model Managers in Django - Composition over Inheritance?

One of the things we got stuck on while designing a new Django project was the necessity of a Database Abstraction Layer, until we realised that the model managers in Django is the DAL. However, we needed more control over the specifics of data retrieval than what Django provided. The resulting consensus? To write custom managers, providing us the application-specific functionality we needed.

But, my custom managers would look something like this.

from django.db import models

class PollManager(models.Manager):
    def get_all(self):
        return OpinionPoll.objects.all()

class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    poll_date = models.DateField()
    objects = PollManager()

This works beautifully (for now). But I can see at least two major issues with this design (and it's not me alone)

  • I won't ever be able to unit test my Manager properly, because it is very tightly coupled with the Django framework code.
  • Say I wrote three custom methods in my manager, and it provides 20 on it's own. If my manager breaks, all 23 methods start failing together - when it should have really been the three which I wrote on my own.

I figured out a possible way to work around this - using composition over inheritance. In other words, I write a custom class (no inheritance) to provide me the queries I wrote in it, and in it I use the default manager to provide me stuff from the database. If my custom class fails, the default manager still works fine.

from django.db import models

class PollManager(cls):
    manager = models.Manager()
    manager.model = type(cls)
    def get_all(self):
        return manager.all()

class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    poll_date = models.DateField()
    custom_manager = PollManager(self)

There might be a very good reason to not do this since I couldn't find it anywhere on the web, but I cannot figure out what that might be. Can someone tell me why I should or shouldn't be doing this?

Aucun commentaire:

Enregistrer un commentaire