Django Reversion

1.7k views Asked by At

I want to undo my last POST/PUt/DELETE or any sort of transaction within a database. I read about Django-reversion & tried implementing it. But to no luck. Here's my code. Please confirm what wrong am I doing!!!

Models to be reversed :-

@reversion.register
class Shipment(models.Model):
    job_id = models.CharField(max_length = 255)
    time = models.DateTimeField( auto_now_add = True, db_index = True)

@reversion.register
class ShipmentScanMapping(models.Model):
    arm_id = models.CharField(max_length = 255)
    status = models.CharField(max_length = 255)
    barcode = models.CharField(max_length = 255)
    reference_number = models.CharField(max_length = 255)
    customer_name = models.CharField(max_length = 255)
    shipment = models.ForeignKey('Shipment',related_name ='scans')
    time = models.DateTimeField( auto_now_add = True)

Views

@csrf_exempt
@reversion.create_revision()
def db_commit(request):

    arm_id = scan_status = barcode = reference_number = customer_name = job_id = 12
    if request.is_ajax():
        shipment_obj = Shipment(job_id = job_id)
        shipment_obj.save()

        ShipmentScanMapping.objects.create(arm_id = arm_id,status = scan_status,barcode = barcode,reference_number = reference_number,
                                                customer_name = customer_name ,shipment= shipment_obj)

        return HttpResponse(json.dumps('Success'), content_type = "application/json")        

@csrf_exempt
def db_undo(request):
    job_id = 12 # just for demo purpose
    shipment_obj = Shipment.objects.filter(job_id = job_id).order_by('-time')[0]

    your_model = ShipmentScanMapping.objects.get(shipment = shipment_obj)
    version_list = reversion.get_unique_for_object(your_model)[0]
    #version_data = version_list.field_dict
    #print version_data
    version_list.revert()

    return HttpResponse(json.dumps('Success'), content_type = "application/json")        

What wrong am I doing ??

1

There are 1 answers

5
Alex Lisovoy On

In your example you just create new object. In this case django-reversion create initial state reversion for this object, but django-reversion allows you to roll back to the state of any previous revision. So modify your ShipmentScanMapping object and try again.

Update

Initialize data:

>>> import reversion
>>> with reversion.create_revision():
...     shipment_obj = Shipment(job_id = 12)
...     shipment_obj.save()
...
>>> reversion.get_unique_for_object(shipment_obj)
[<Version: Shipment object>]
>>> with reversion.create_revision():
...     your_model = ShipmentScanMapping.objects.create(arm_id = 12,status = 12,barcode = 12,reference_number = 12,customer_name =12,shipment=shipment_obj)
...
>>> reversion.get_unique_for_object(your_model)
[<Version: ShipmentScanMapping object>]
>>> your_model.arm_id
12
>>> your_model.id
1

Update data:

>>> with reversion.create_revision():
...     your_model.arm_id=15
...     your_model.save()
...
>>> reversion.get_unique_for_object(your_model)
[<Version: ShipmentScanMapping object>, <Version: ShipmentScanMapping object>]
>>> ShipmentScanMapping.objects.get(id=1).arm_id
15
>>> [r.field_dict.get('arm_id') for r in reversion.get_unique_for_object(your_model)]
[u'15', u'12']

Revert:

>>> rev = reversion.get_unique_for_object(your_model)[-1]
>>> rev.field_dict.get('arm_id')
u'12'
>>> rev.revert()
>>> ShipmentScanMapping.objects.get(id=1).arm_id

Update2

Can I revert only those changes which have been updated(PUT) or any POST/DELETE request can also be revert?

You can also recover a deleted object, see docs.

How can I revert upto nth level?? Does [-1] means the DB will be reverted to the latest update?

get_unique_for_object method returns a list of all previous versions, latest versions first. So you can select as usual selection from the list in python. By the way you can find the most recent version for a given date:

rev = reversion.get_for_date(your_model, datetime.datetime(2008, 7, 10))

Update3

if initially, the value was 3 and was updated with 12 and then reverted back to 3. What happens with the value 12?? Also, how would I revert back an insert(POST) query, eg:- if I inserted 12 and then I want to revert this change?

Okay, let's consider how it works. When you register your model, the django-reversion begins to watch post_save signals from the model. Whenever you save changes to a model, it is serialized using the Django serialization framework into a JSON string and save it to the database as a reversion.models.Version model.

So when you need reverting some version, django-reversion load the appropriate Version model from the database, deserializing the model data, and re-saving the old data. During the re-saving the current state will be lost if not called method save. If it was called, the state will be stored in appropriate version(see text above).

If you need revert just created object, you should remove it manually.