soynatan / django-easy-audit

Yet another Django audit log app, hopefully the simplest one.
GNU General Public License v3.0
735 stars 182 forks source link

Model inheritance: CRUDEvent object_json_repr doesn't include parent model fields #255

Open marko90b opened 1 year ago

marko90b commented 1 year ago

This is due to django's Serializer includes only local fields: Django #7350

It could be handled in one of these ways:

marko90b commented 1 year ago

Solved with an ugly callback: (not tested on instances with multiple inheritance, but it should work)

from django.db.models import signals

def create_crud_for_parent_class(
    instance, object_json_repr, created, raw, using, update_fields, **kwargs
):
    #* Callback must return True, otherwise CRUDEvent for instance is not logged
    # If not child class instance, exit
    if not type(instance)._meta.parents:
        return True
    # Determine if this is post_save or pre_save signal
    signal_type = 'post_save' if 'created' in kwargs['signal'].providing_args else 'pre_save'
    # On pre_save, not created CRUDevents are logged -> exit if opposite
    if signal_type == 'pre_save' and created:
        return True
    # On post_save, created CRUDevents are logged -> exit if opposite
    if signal_type == 'post_save' and not created:
        return True

    # If CRUDEvent should be logged, loop through instance's parents (if it has them)
    for parent_model, parent_field in type(instance)._meta.parents.items():
        # get parent instance
        parent_instance = getattr(instance, parent_field.name, None)
        if parent_instance:
            # if parent instance exists, send appropriate signal
            # NOTE: pre_save doesn't accept 'created' arg, post_save does
            signal = getattr(signals, signal_type)
            kwargs = {'raw': raw, 'using': using, 'update_fields': update_fields}
            if signal_type == 'post_save':
                kwargs['created'] = created
            signal.send(parent_instance.__class__, instance=parent_instance, **kwargs)
    return True

BTW: Does anyone know if there is a leaner approach how to determine if callback was called from pre_save or post_save signal?