django-diffs tutorial

This is a walkthrough tutorial demonstrating the features of django diffs


In [1]:
# Setup django
import os
os.environ['DJANGO_SETTINGS_MODULE'] =  'example.settings'
import django
django.setup()

Configuring django-diffs


In [2]:
from django.conf import settings
settings.DIFFS_SETTINGS


Out[2]:
{'test_mode': True, 'use_transactions': False}

In [3]:
from diffs.settings import diffs_settings
diffs_settings


Out[3]:
{'max_element_age': 3600,
 'redis': {'db': 0, 'host': 'localhost', 'port': 6379},
 'test_mode': True,
 'use_transactions': False}

Using django-diffs

1. Register Model class


In [4]:
# create model and register via decorator
import diffs
from django.db import models

@diffs.register
class Report(models.Model):
    
    name = models.CharField(max_length=255)
    min_value = models.IntegerField()
    max_value = models.IntegerField()
    
    class Meta:
        app_label = 'example'

In [5]:
# run migrate to create the tables
from django.core.management import call_command
call_command('makemigrations')
call_command('migrate')


Migrations for 'example':
  example/migrations/0001_initial.py:
    - Create model Report
Operations to perform:
  Apply all migrations: auth, contenttypes, example, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying example.0001_initial... OK
  Applying sessions.0001_initial... OK

2. Make a change via a model instance


In [6]:
# simple diff
report = Report(name='Python Report', min_value=10, max_value=100)
report.save()

3. ???

4. Profit


In [7]:
print report.diffs


[<diffs.models.Diff object at 0x10b6c8f90>]

In [8]:
diff = report.diffs[0]
print diff.timestamp
print diff.data
print diff.created


1.47872263919e+12
[{u'pk': 1, u'model': u'example.report', u'fields': {u'max_value': 100, u'min_value': 10, u'name': u'Python Report'}}]
True
Out[8]:
"<Diff [{u'pk': 1, u'model': u'example.report', u'fields': {u'max_value': 100, u'min_value': 10, u'name': u'Python Report'}}]>"

Custom Serialization


In [11]:
@diffs.register
class Report(models.Model):
    
    name = models.CharField(max_length=255)
    min_value = models.IntegerField()
    max_value = models.IntegerField()
    
    class Meta:
        app_label = 'example'
        
    def serialize_diff(self, dirty_fields):
        if 'name' in dirty_fields:
            return {'name': self.name}
        else:
            return None


/usr/local/lib/python2.7/site-packages/django/db/models/base.py:310: RuntimeWarning: Model 'example.report' was already registered. Reloading models is not advised as it can lead to inconsistencies, most notably with related models.
  new_class._meta.apps.register_model(new_class._meta.app_label, new_class)

In [12]:
report = Report(name='bay area report', min_value=5, max_value=7)
report.save()

In [13]:
report.min_value = 4
report.save()

In [14]:
report.diffs


Out[14]:
[<diffs.models.Diff at 0x103d3a910>]

In [15]:
report.diffs[0].data


Out[15]:
{u'name': u'bay area report'}

In [16]:
# related models
@diffs.register
class ReportItem(models.Model):
    
    report = models.ForeignKey('Report')
    important_value = models.IntegerField()
    status = models.CharField(max_length=255)
    
    class Meta:
        app_label = 'example'
    
    def get_diff_parent(self):
        return self.report

In [17]:
call_command('makemigrations')
call_command('migrate')


Migrations for 'example':
  example/migrations/0002_reportitem.py:
    - Create model ReportItem
Operations to perform:
  Apply all migrations: auth, contenttypes, example, sessions
Running migrations:
  Applying example.0002_reportitem... OK

In [18]:
report_item = ReportItem(status='OK', important_value=9001, report=report)
report_item.save()

In [19]:
report.diffs


Out[19]:
[<diffs.models.Diff at 0x103d6f850>, <diffs.models.Diff at 0x103d6fd10>]

In [20]:
for diff in report.diffs:
    print diff.data


{u'name': u'bay area report'}
[{u'pk': 1, u'model': u'example.reportitem', u'fields': {u'status': u'OK', u'important_value': 9001}}]

Advanced Querying

django-diffs stores the diffs in a redis sorted set

You can get a SortedSet instance from the class manager.


In [21]:
# query interface
sorted_set = Report.diffs.get_sortedset(report.id)
print sorted_set.min_score
print sorted_set.max_score


1.47872180904e+12
1.47872190272e+12

In [23]:
sorted_set.zrevrangebyscore('+inf', '-inf', withscores=True)


Out[23]:
[<diffs.models.Diff at 0x103d6fad0>, <diffs.models.Diff at 0x103d6ff10>]

In [ ]: