Context should not inherit from models.Model, as it already has that in the inheritance chain from the mixins themselves. You may also need to remove models.Model from FullAuditMixin, for the same reason.
Django: using mixins for common model fields
-
12-10-2022 - |
Question
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.
Solution