pythondjangodjango-reversion

split the revision.comment into field and value in Django-reversion


I have a function to display history list of version objects as below and I have this particular .py file in public repo at https://github.com/praneethkumarpidugu/django-reversion/blob/master/rev_history/views.py#L1:

from django.http import HttpResponse
from reversion.models import Version
#from django.contrib.admin.models import LogEntry
import json

def history_list(request):
    history_list = Version.objects.all().order_by('-revision__date_created')

    data = []

    for i in history_list:
        data.append({
            'date_time': str(i.revision.date_created),
            'user': str(i.revision.user),
            'object': i.object_repr,
            'type': i.content_type.name,
            'comment': i.revision.comment
        })

    data_ser = json.dumps(data)
    return HttpResponse(data_ser, content_type="application/json")

To change the object entities I visited admin page 127.0.0.1:8000/admin I changed a boolean field for representation say "is_active" from true to false.

Now, I come to history page 127.0.0.1:8000/history

I see the json data as below:

{"type": "model a", "date_time": "2015-03-04 15:58:36.141569+00:00", **"comment": "Changed is_active."**, "object": "ModelA object", "user": "admin1"}

Solution likely to have: I want comment to be split as previous_value: "True", "new_value": "False", "field": "is_active".

my research driving towards solution I digged into Revision class of reversion/models.py to see if there are any extra arguements to display field and value but to my understanding I'm unable to find the clue where I could find field and values for comment. for reference here is the comment from Revision

comment = models.TextField(blank=True,
                               verbose_name=_("comment"),
                               help_text="A text comment on this revision.")

solution to represent field : This might look a bit silly but I just hacked into my own data of comment above to represent field as

  'field': i.revision.comment.split(' ')[-1] 

But I still need to get the values of the field which are original and new values after changing.


Solution

  • I hope I understood the problem properly, here's the half baked solution to it:

    from django.db.models.signals import pre_save
    from django.dispatch import receiver
    import reversion
    
    @receiver(pre_save)
    def _pre_save(sender, **kwargs):
        _i = kwargs.get('instance')
        _i_old = sender.objects.get(pk=_i.pk)
        _current, _past = set(_i.__dict__.keys()), set(_i_old.__dict__.keys())
        _intersection = _current.intersection(_past)
        _changed_keys = set(o for o in _intersection if _i.__dict__[o] != _i_old.__dict__[o])
        _comment = ['changed {} from {} to {}'.format(_, _i_old.__dict__[_], _i.__dict__[_]) for _ in _changed_keys]
        reversion.set_comment(', '.join(_comment))
    

    Haven't thought much about the performance overhead, but this should do the trick.

    Hope this helps.