2015-02-16 21:17:22 +00:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
2015-02-16 16:06:17 +00:00
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
2015-06-03 13:50:41 +00:00
|
|
|
from django.db.models import Model, NOT_PROVIDED
|
2015-02-16 21:17:22 +00:00
|
|
|
from django.utils.encoding import smart_text
|
2013-10-20 13:25:48 +00:00
|
|
|
|
|
|
|
|
|
2015-06-03 14:06:25 +00:00
|
|
|
def get_fields_in_model(instance):
|
|
|
|
|
"""
|
|
|
|
|
Returns the list of fields in the given model instance. Checks whether to use the official _meta API or use the raw
|
|
|
|
|
data. This method excludes many to many fields.
|
|
|
|
|
|
|
|
|
|
:param instance: The model instance to get the fields for
|
|
|
|
|
:type instance: Model
|
|
|
|
|
:return: The list of fields for the given model (instance)
|
|
|
|
|
:rtype: list
|
|
|
|
|
"""
|
2015-07-21 22:03:54 +00:00
|
|
|
from auditlog.models import AuditlogHistoryField
|
2015-06-03 14:06:25 +00:00
|
|
|
assert isinstance(instance, Model)
|
|
|
|
|
|
|
|
|
|
# Check if the Django 1.8 _meta API is available
|
|
|
|
|
use_api = hasattr(instance._meta, 'get_fields') and callable(instance._meta.get_fields)
|
|
|
|
|
|
|
|
|
|
if use_api:
|
2015-07-21 22:03:54 +00:00
|
|
|
return [f for f in instance._meta.get_fields() if not (f.many_to_many or isinstance(f, AuditlogHistoryField))]
|
2015-06-03 14:06:25 +00:00
|
|
|
return instance._meta.fields
|
|
|
|
|
|
|
|
|
|
|
2014-10-03 13:13:03 +00:00
|
|
|
def model_instance_diff(old, new, **kwargs):
|
2013-10-20 13:25:48 +00:00
|
|
|
"""
|
|
|
|
|
Calculate the differences between two model instances. One of the instances may be None (i.e., a newly
|
2015-06-03 13:50:41 +00:00
|
|
|
created model or deleted model). This will cause all fields with a value to have changed (from the fields default
|
|
|
|
|
value).
|
2013-10-20 13:25:48 +00:00
|
|
|
"""
|
2014-10-03 13:13:03 +00:00
|
|
|
from auditlog.registry import auditlog
|
|
|
|
|
|
2013-10-20 13:25:48 +00:00
|
|
|
if not(old is None or isinstance(old, Model)):
|
2015-02-16 21:17:22 +00:00
|
|
|
raise TypeError("The supplied old instance is not a valid model instance.")
|
2013-10-20 13:25:48 +00:00
|
|
|
if not(new is None or isinstance(new, Model)):
|
2015-02-16 21:17:22 +00:00
|
|
|
raise TypeError("The supplied new instance is not a valid model instance.")
|
2013-10-20 13:25:48 +00:00
|
|
|
|
|
|
|
|
diff = {}
|
|
|
|
|
|
|
|
|
|
if old is not None and new is not None:
|
2015-06-03 14:06:25 +00:00
|
|
|
fields = set(get_fields_in_model(old) + get_fields_in_model(new))
|
2014-10-03 13:13:03 +00:00
|
|
|
model_fields = auditlog.get_model_fields(new._meta.model)
|
2013-10-20 13:25:48 +00:00
|
|
|
elif old is not None:
|
2015-06-03 14:06:25 +00:00
|
|
|
fields = set(get_fields_in_model(old))
|
2014-10-03 13:13:03 +00:00
|
|
|
model_fields = auditlog.get_model_fields(old._meta.model)
|
2013-10-20 13:25:48 +00:00
|
|
|
elif new is not None:
|
2015-06-03 14:06:25 +00:00
|
|
|
fields = set(get_fields_in_model(new))
|
2014-10-03 13:13:03 +00:00
|
|
|
model_fields = auditlog.get_model_fields(new._meta.model)
|
2013-10-20 13:25:48 +00:00
|
|
|
else:
|
|
|
|
|
fields = set()
|
2015-02-16 16:06:17 +00:00
|
|
|
model_fields = None
|
2013-10-20 13:25:48 +00:00
|
|
|
|
2014-10-03 13:13:03 +00:00
|
|
|
# Check if fields must be filtered
|
2015-02-16 16:06:17 +00:00
|
|
|
if model_fields and (model_fields['include_fields'] or model_fields['exclude_fields']) and fields:
|
2014-10-03 13:13:03 +00:00
|
|
|
filtered_fields = []
|
|
|
|
|
if model_fields['include_fields']:
|
|
|
|
|
filtered_fields = [field for field in fields
|
|
|
|
|
if field.name in model_fields['include_fields']]
|
|
|
|
|
else:
|
|
|
|
|
filtered_fields = fields
|
|
|
|
|
if model_fields['exclude_fields']:
|
|
|
|
|
filtered_fields = [field for field in filtered_fields
|
|
|
|
|
if field.name not in model_fields['exclude_fields']]
|
|
|
|
|
fields = filtered_fields
|
|
|
|
|
|
2013-10-20 13:25:48 +00:00
|
|
|
for field in fields:
|
2015-02-16 16:06:17 +00:00
|
|
|
try:
|
2015-06-03 13:50:41 +00:00
|
|
|
old_value = getattr(old, field.name, None)
|
2015-02-16 16:06:17 +00:00
|
|
|
except ObjectDoesNotExist:
|
2015-06-03 13:50:41 +00:00
|
|
|
old_value = field.default if field.default is not NOT_PROVIDED else None
|
2015-02-16 16:06:17 +00:00
|
|
|
|
|
|
|
|
try:
|
2015-06-03 13:50:41 +00:00
|
|
|
new_value = getattr(new, field.name, None)
|
2015-02-16 16:06:17 +00:00
|
|
|
except ObjectDoesNotExist:
|
|
|
|
|
new_value = None
|
2013-10-20 13:25:48 +00:00
|
|
|
|
|
|
|
|
if old_value != new_value:
|
2015-06-03 13:50:41 +00:00
|
|
|
diff[field.name] = (smart_text(old_value), smart_text(new_value))
|
2013-10-20 13:25:48 +00:00
|
|
|
|
|
|
|
|
if len(diff) == 0:
|
|
|
|
|
diff = None
|
|
|
|
|
|
|
|
|
|
return diff
|