1

I've defined a base abstract model class which gives some extra funcionality to the model, like this:

class BaseModel(models.Model):
    # ... some fields and methods
    class Meta:
        abstract = True

class Model1(BaseModel):
    # ... some fields and methods
    def required_method(self, *args, *kwargs):
        # implementation

class Model2(BaseModel):
    # ... some fields and methods

Now I need to ensure, that each derived class has number of required methods defined. If any of them is not defined, I need to throw an exception on attempt of execution by manage.py. So in other words, BaseModel should require each derived class to define some interfaces, that this BaseModel uses, but not defines by itself.

Where should I implement this checking? Is the __init__ of the BaseModel a good place to check this?

Edit: Purpose of this is just for safety. If somebody or me after some time, will try to inherit from BaseModel class, but forgets to implement required methods, the code will still run until BaseModel code tries to execute any missing method. So it's potentially dangerous to me. It's better to prevent such code from execution. I believe that Java has such mechanism called interfaces. I'd like to do something similar in Python.

Dzejkob
  • 2,302
  • 2
  • 15
  • 20
  • 1
    No. `__init__` is not a good plase to do checks like this beacuse they will run each time you create an instance of the model. Why you don't want to declare these methods in `BaseModel` that just raise an `NotImplementedException`? – Pavel Reznikov Jul 18 '12 at 13:17
  • What @troolee said. The _point_ of base classes is that they define methods that the children inherit or override. – Katriel Jul 18 '12 at 13:25
  • if you want to do some checks that verify children of `BaseModel`, I suggest you to add management command or test case that will load all nested classes and check 'em. I think it's not a good idea to do these checks on server start or befere request, etc. – Pavel Reznikov Jul 18 '12 at 13:35
  • In my case there are some methods that are used by common code of the BaseModel, but canno't be defined in it, because their implementation differs. For example each child class should define `is_editable()` method returning True or False. @troolee, yes I did that before, but it's dangerous, because I'll only get exception when they are executed, until then it will look fine, which I want to avoid. I need to be able to execute only when I'm sure that all child classes are properly implemented. – Dzejkob Jul 18 '12 at 13:38
  • @Dzejkob move these checks on test case and run `./manage.py test` before running server – Pavel Reznikov Jul 18 '12 at 13:41
  • @troolee: It's good when You are generally using tests and TDD. I don't use tests for other purposes, so it would be strange to run them only for that purpose. But Django does some checks on models on server start, stopping excecution if for example `related_name` clashes with the other model. So it would be ideal for me to just mimic that behavior somehow. – Dzejkob Jul 18 '12 at 13:47
  • @Dzejkob you could create management command `check_all_my_models` and do these checks there. Or look at http://stackoverflow.com/questions/5439650/how-to-run-arbitrary-code-after-django-is-fully-loaded You can write an middleware that will make your checks in `__init__` and after that will rise an `MiddlewareNotUsed` exception. See https://docs.djangoproject.com/en/1.4/topics/http/middleware/#marking-middleware-as-unused – Pavel Reznikov Jul 18 '12 at 13:55

1 Answers1

2

Use the decorators in the abc package to mark which methods should be abstract. The package takes care of the checking for you, so you don't even have to worry about a proper location for your checks ;-)

dr. Sybren
  • 829
  • 5
  • 18
  • Great. That's what I was looking for. – Dzejkob Jul 18 '12 at 18:49
  • Apparently I'm having some difficulties applying that solution. As I understand it, the `abc.abstractmethod` decorator won't work unless I set `__metaclass__= abc.ABCMeta`. But if I do this on Django model class, I'm getting: `TypeError: Error when calling the metaclass bases; metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases`. I'm not familiar with this metaclasses concept, so is there any simple solution to this? – Dzejkob Jul 20 '12 at 10:14