model = TrackModel(Contact) name = models.CharField(max_length=100)
The RevisionLog is a normal abstract model with some fields on it. The app works by creating SQL triggers that create a new RevisionLog every time a change is made to the model being tracked, basically an audit trail.
If you don't like SQL triggers please keep it to yourself, I'm aware of the signals framework...
Anyways, I've poured over the migrations autodetector and related code and there doesn't appear to be any possible way to hook into it. So my solution right now is to provide my own makemigrations management command which silently replaces the built in one (I had no idea Django allowed you to do this without patching). The command looks like this:
from django.core.management.commands import makemigrations from my_app.migration_ops import inspect_changes
class Command(makemigrations.Command): def write_migration_files(changes): """ Override here so we can inspect the changes and possibly insert our own operations """ changes = inspect_changes(changes) super(Command, self).write_migration_files(changes)
So that works well enough and at least I have some reasonable way to hook into makemigrations and insert my own operations. The idea is that a user of my_app can run makemigrations like normal and the appropriate operations will be generated, including operations that manage the SQL triggers that I need.
The last big hurdle to get this working the way I want is that Django doesn't allow custom attributes on Model.Meta. The copy_fields option seen above has an effect on the SQL trigger that is generated, so if a user changes its value and runs makemigrations a new migration should be made. Changes made to the builtin meta options are picked up by the migrations autodetector so I assumed I could take advantage of that and define my own but Django validates all the attributes.
It looks like my options are to either:
monkeypatch the list of allowed meta options, although I'm wary that this might have strange side effects elsewhere
use an attribute directly on the model class, but then there's no obvious way to have the migrations autodetector pick this up
Re: Custom Model.Meta Options and Extending Migrations Autodetection
I actually ended up solving this a different way. The RevisionLog model classes are required to have a TrackModel field defined, so I made copy_fields an option defined on the field instead of the model/meta. So I have something like:
from django.db import models
classTrackModel(models.ForeignKey): def __init__(self, to, copy_fields,**kwargs): self.copy_fields = copy_fields super(TrackModel,self).super(to,**kwargs)
This is actually a nicer api for my use case, doesn't require any hacks/patches, and the migration autodetector will pick up changes.
Now the only problem I have is trying to figure out how to reference an implicit m2m through model in a FK field.... Given a m2m field, the through attribute is apparently abstract and so can't be referenced without requiring an explicit through model.