Commit 7772bc58 authored by Daniel Klaffenbach's avatar Daniel Klaffenbach 🐍

models: Minor PEP-related fixes

parent f99343cf
......@@ -19,18 +19,19 @@ from . import _thread_local_storage
logger = logging.getLogger(__name__)
class JournalEntryManager(models.Manager):
use_for_related_fields = True
def get_content_type_filter(self, with_children=False, with_parents=False):
if not hasattr(self, 'instance'):
return None
content_type_filter = Q(
Q(content_type__app_label=self.instance._meta.app_label) &
Q(content_type__model=self.instance.__class__.__name__.lower())
)
if with_children:
for cls in apps.get_models():
if issubclass(cls, self.instance.__class__) and cls != self.instance.__class__:
......@@ -38,16 +39,15 @@ class JournalEntryManager(models.Manager):
Q(content_type__app_label=cls._meta.app_label) &
Q(content_type__model=cls.__name__.lower())
)
if with_parents:
for cls in self.instance._meta.get_parent_list():
content_type_filter |= Q(
Q(content_type__app_label=cls._meta.app_label) &
Q(content_type__model=cls.__name__.lower())
)
Q(content_type__app_label=cls._meta.app_label) &
Q(content_type__model=cls.__name__.lower())
)
return content_type_filter
def with_children(self):
"""
Useful for related managers to get the full journal for the model,
......@@ -58,7 +58,7 @@ class JournalEntryManager(models.Manager):
else:
content_type_filter = self.get_content_type_filter(with_children=True)
return self.model.objects.filter(object_id=self.instance.pk).filter(content_type_filter)
def with_parents(self):
"""
Useful for related managers to get the full journal for the model,
......@@ -77,50 +77,51 @@ class JournalEntry(models.Model):
Contains all logs for all models. The objects are referenced through a
GenericForeignKey and the attributes are stored in a JSON field.
"""
OPERATION_ADD = 1
OPERATION_ADD = 1
OPERATION_CHANGE = 2
OPERATION_DELETE = 3
OPERATION_CHOICES = (
(OPERATION_ADD, _('Created')),
(OPERATION_CHANGE, _('Changed')),
(OPERATION_DELETE, _('Deleted'))
)
user = models.CharField(db_index=True, editable=False, max_length=100)
time = models.DateTimeField(auto_now_add=True, editable=False)
operation = models.PositiveSmallIntegerField(choices=OPERATION_CHOICES, db_index=True, editable=False)
content_type = models.ForeignKey(ContentType, editable=False)
object_id = models.CharField(db_index=True, editable=False, max_length=255)
instance = GenericForeignKey('content_type', 'object_id')
object_id = models.CharField(db_index=True, editable=False, max_length=255)
instance = GenericForeignKey('content_type', 'object_id')
attrs = JSONField(editable=False)
objects = JournalEntryManager()
class Meta:
ordering = ('id', )
ordering = ('id',)
def __str__(self):
return "JournalEntry from %s" %date_format(self.time, "SHORT_DATETIME_FORMAT")
return "JournalEntry from %s" % date_format(self.time, "SHORT_DATETIME_FORMAT")
def _get_last_entry(self):
"""
Returns the predecessor of this JournalEntry.
:rtype: JournalEntry | None
"""
return self.__class__.objects.filter(content_type=self.content_type, object_id=self.object_id, pk__lt=self.pk).last()
return self.__class__.objects.filter(content_type=self.content_type, object_id=self.object_id,
pk__lt=self.pk).last()
def get_diff(self):
last = self._get_last_entry()
if last:
attrs_last = last.attrs
else:
attrs_last = {}
diff = {}
for attr in self.attrs:
if attr not in attrs_last:
......@@ -128,11 +129,11 @@ class JournalEntry(models.Model):
elif attrs_last[attr] != self.attrs[attr]:
diff[attr] = (attrs_last[attr], self.attrs[attr])
return diff
def get_changed_attributes(self):
if self.operation == self.OPERATION_ADD:
return []
last = self._get_last_entry()
if not last:
return []
......@@ -148,39 +149,39 @@ class JournalEntry(models.Model):
if self.operation == self.OPERATION_CHANGE:
attrs = ', '.join(self.get_changed_attributes())
if not attrs:
return ugettext('%s was saved without any changes.' %self.instance._meta.verbose_name)
return ugettext('%s was saved without any changes.' % self.instance._meta.verbose_name)
else:
return ugettext('Changed attributes: %s' %attrs)
return ugettext('Changed attributes: %s' % attrs)
elif self.operation == self.OPERATION_ADD:
return ugettext('%s was added.' %self.instance._meta.verbose_name)
return ugettext('%s was added.' % self.instance._meta.verbose_name)
else:
return ugettext('%s was deleted.' %self.instance._meta.verbose_name)
return ugettext('%s was deleted.' % self.instance._meta.verbose_name)
def get_display_full(self):
verbose_name = self.instance._meta.verbose_name
if self.operation == self.OPERATION_ADD:
label = ugettext('%s was added.' %verbose_name)
label = ugettext('%s was added.' % verbose_name)
li = ''
for attr in self.attrs:
if self.attrs[attr]:
li += format_html('<li><strong>{}:</strong> "{}"</li>', attr, self.attrs[attr])
if li:
label += '<ul>%s</ul>' %li
label += '<ul>%s</ul>' % li
return mark_safe(label)
elif self.operation == self.OPERATION_CHANGE:
diff = self.get_diff()
if not diff:
return ugettext('%s was saved without any changes.' %self.instance._meta.verbose_name)
return ugettext('%s was saved without any changes.' % self.instance._meta.verbose_name)
else:
label = ugettext('%s was changed:' %verbose_name)
label = ugettext('%s was changed:' % verbose_name)
li = ''
for i in diff:
li += format_html('<li><strong>{}:</strong> "{}" &rarr; "{}"</li>', i, diff[i][0], diff[i][1])
li += format_html('<li><strong>{}:</strong> "{}" &rarr; "{}"</li>', i, diff[i][0], diff[i][1])
if li:
label += '<ul>%s</ul>' %li
label += '<ul>%s</ul>' % li
return mark_safe(label)
else:
return ugettext('%s was deleted.' %verbose_name)
return ugettext('%s was deleted.' % verbose_name)
class Journal(GenericRelation):
......@@ -190,30 +191,29 @@ class Journal(GenericRelation):
def contribute_to_class(self, cls, name):
super(Journal, self).contribute_to_class(cls, name)
# Monkey-patch the model class if it does not define a
# `get_journal_entry_username` method.
if not hasattr(cls, 'get_journal_entry_username'):
setattr(cls, 'get_journal_entry_username', get_journal_entry_username)
else:
logger.debug("Using get_journal_entry_username() provided by model %s." %cls.__name__)
logger.debug("Using get_journal_entry_username() provided by model %s." % cls.__name__)
if not hasattr(cls, '_MODEL_JOURNAL_ATRR'):
setattr(cls, '_MODEL_JOURNAL_ATRR', name)
elif cls._MODEL_JOURNAL_ATRR != name:
logger.error("Multiple Journal relations defined for model %s." %cls.__name__)
logger.error("Multiple Journal relations defined for model %s." % cls.__name__)
return
models.signals.post_save.connect(self.post_save, sender=cls, weak=False)
models.signals.post_delete.connect(self.post_delete, sender=cls, weak=False)
def create_journal_entry(self, instance, operation):
attrs = {}
for field in instance._meta.fields:
if field.attname not in self._exclude:
attrs[field.attname] = getattr(instance, field.attname)
JournalEntry.objects.create(
user=instance.get_journal_entry_username(),
operation=operation,
......@@ -230,7 +230,7 @@ class Journal(GenericRelation):
self.create_journal_entry(instance, operation)
def post_delete(self, instance, **kwargs):
self.create_journal_entry(instance, JournalEntry.OPERATION_DELETE)
self.create_journal_entry(instance, JournalEntry.OPERATION_DELETE)
def get_journal_entry_username(self):
......@@ -248,7 +248,7 @@ def get_journal_entry_username(self):
return getattr(_thread_local_storage, 'model_journal_username')
except AttributeError:
if 'model_journal.middleware.ModelJournalMiddleware' not in getattr(settings, 'MIDDLEWARE_CLASSES', []) and \
'model_journal.middleware.ModelJournalMiddleware' not in getattr(settings, 'MIDDLEWARE', []):
'model_journal.middleware.ModelJournalMiddleware' not in getattr(settings, 'MIDDLEWARE', []):
raise ImproperlyConfigured(
"The ModelJournalMiddleware is missing from your MIDDLEWARE_CLASSES"
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment