I am trying to create mixins that would represent commonly used fields within a database. In this example, it is extremely common for a database table to track when the record was created, who created it, when it was edited, and who edited it. To do this I have created the following mixins:
[project]/libs/mixins/CreationAuditMixin.py:
from django.db import models
class CreationAuditMixin(models.Model):
""" CreationAuditMixin documentation
"""
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.CharField(max_length=255, blank=True, editable=False)
class Meta:
abstract = True
[project]/libs/mixins/ModificationAuditMixin.py:
from django.db import models
class ModificationAuditMixin(models.Model):
""" ModificationAuditMixin documentation
"""
modified_at = models.DateTimeField(auto_now=True)
modified_by = models.CharField(max_length=255, blank=True, editable=False)
class Meta:
abstract = True
[project]/libs/mixins/FullAuditMixin.py (just for convenience):
from django.db import models
from libs.mixins.audit import CreationAuditMixin, ModificationAuditMixin
class FullAuditMixin(models.Model, CreationAuditMixin, ModificationAuditMixin):
class Meta:
abstract = True
[project]/libs/models/questions/Context.py:
from django.db import models
from libs.mixins.audit import FullAuditMixin, CreationAuditMixin, ModificationAuditMixin
_app_label = 'questions'
_db_table = '\".\"'.join((_app_label, 'context'))
class Context(models.Model, FullAuditMixin):
""" Model representing a Context
"""
_format_string = "{}: {}, {} - {}"
name = models.CharField(max_length=255)
description = models.CharField(max_length=2000)
publish_start = models.DateTimeField()
publish_end = models.DateTimeField()
def __unicode__(self):
""" Returns a unicode representation of the model
"""
result = self._format_string.format(self.name, self.description, self.publish_start, self.publish_end)
return result
class Meta:
app_label = _app_label
db_table = _db_table
I may move the models into their specific app file structure at a later time but for now there is already manual configuration around schema/app_label/db_table so this structure does not contribute additional configuration.
When attempting anything that imports Context (most manage commands, in this case, attempting a migration) I receive the following error:
./manage.py schemamigration questions --initial
Traceback (most recent call last):
File "./manage.py", line 20, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 392, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 242, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 284, in execute
self.validate()
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 310, in validate
num_errors = get_validation_errors(s, app)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/validation.py", line 34, in get_validation_errors
for (app_name, error) in get_app_errors().items():
File "/usr/local/lib/python2.7/dist-packages/django/db/models/loading.py", line 196, in get_app_errors
self._populate()
File "/usr/local/lib/python2.7/dist-packages/django/db/models/loading.py", line 75, in _populate
self.load_app(app_name, True)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/loading.py", line 99, in load_app
models = import_module('%s.models' % app_name)
File "/usr/local/lib/python2.7/dist-packages/django/utils/importlib.py", line 40, in import_module
__import__(name)
File "./apps/questions/models.py", line 1, in <module>
from libs.models.questions import Context
File "./libs/models/questions/Context.py", line 3, in <module>
from libs.mixins.audit import FullAuditMixin, CreationAuditMixin, EditAuditMixin
File "./libs/mixins/audit/FullAuditMixin.py", line 5, in <module>
class FullAuditMixin(models.Model, CreationAuditMixin, EditAuditMixin):
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 79, in __new__
new_class = super_new(cls, name, bases, {'__module__': module})
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
When I built these mixins, I had already consulted Django: Creating a Mixin for Reusable Model Fields and http://www.djangocurrent.com/2011/05/django-aspect-oriented-models.html, my approach was based on reading these. Any ideas on how I can properly structure these mixins and the cause of this error would be appreciated.