Django Reversion
Hint
Refer to the manual for details of how to install and use
django-reversion
. It includes a list of which version of
django-reversion
is compatible with each version of Django - worth keeping
an eye on as the recommended version for the latest version of Django does
change.
Note
On production systems we create a shell script to run django administration
commands where this document refers to django-admin
you should use the
appropriate script on the production system.
History
from contact.models import Contact
contact = Contact.objects.get(pk=12424)
from reversion.models import Version
versions = Version.objects.get_for_object(contact)
for x in versions: print(x.revision.user, x.revision.date_created, x)
Tip
x.field_dict
will display a dictionary showing changes to
individual fields.
Import Signature
From django-reversion
version 1.10 the import signature changed from
import reversion
to:
from reversion import revisions as reversion
Add reversion to a model
To register reversion
on a model e.g:
from reversion import revisions as reversion
@reversion.register()
class ModelWithReversion(models.Model):
# ...
The legacy method is as follows:
class ModelWithReversion(models.Model):
# ...
reversion.register(ModelWithReversion)
If the reversion is added after a model it was initially created you can create initial revision using the management command
django-admin createinitialrevisions your_app.YourModel --comment="Initial revision."
Register
To unregister
models (to stop storing versions while you do some
processing):
import reversion
model_list = [
Contact,
ContactAddress,
ContactEmail,
ContactPhone,
]
for m in model_list:
if reversion.is_registered(m):
reversion.unregister(m)
To register
the same models:
for m in model_list:
if not reversion.is_registered(m):
reversion.register(m)
To make this easier, you could unregister
and then register
in a
try
, finally
block like this:
try:
_unregister()
do_something_useful()
finally:
_register()
Reversion statistics
Count of Revision records
We’ve added a management command to the base app with list the number of revision records for each model in a project.
Note
to use this command, you must be using django-reversion version
2.0.5 or
later
To use the command simply change to the project directory and type:
django-admin revision_count
Space used in the database
The space used by Postgres can be monitored using the command (the reversion
tables are prefixed by reversion_
):
psql -U postgres <database name> -c "select relname, relpages from pg_class order by relpages desc;" | grep "reversion_"jk
A more detailed breakdown can be obtained using
psql -U postgres <database name> -c "SELECT *, pg_size_pretty(total_bytes) AS total
, pg_size_pretty(index_bytes) AS INDEX
, pg_size_pretty(toast_bytes) AS toast
, pg_size_pretty(table_bytes) AS TABLE
FROM (
SELECT *, total_bytes-index_bytes-COALESCE(toast_bytes,0) AS table_bytes FROM (
SELECT c.oid,nspname AS table_schema, relname AS TABLE_NAME
, c.reltuples AS row_estimate
, pg_total_relation_size(c.oid) AS total_bytes
, pg_indexes_size(c.oid) AS index_bytes
, pg_total_relation_size(reltoastrelid) AS toast_bytes
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE relkind = 'r'
) a
) a order by total_bytes desc limit 50;"
Size of reversion tables in backup
To find out how much many lines of the Postgres dump file is given over to reversion:
grep -n "^COPY" <backup file name> > /tmp/bkup-lines.txt
then view the file and search for reversion_
the difference between the line
number of this copy command and the next one gives the number of lines that the
backup of that table spans.
Reversion in not always appropriate
Where a table changes frequently (e.g. for recording stats) it can create a large number of reversion records that serve no useful purpose.
See the next section for how to remove reversion from an existing model.
Remove reversion from an existing model
Note
Before removing an existing model from reversion you should remove the existing revision data otherwise this data will be retained but will not be accessable.
To delete existing revision information use the deleterevisions
management
command as follows:
django-admin deleterevisions <app name>.<Model name>
If there are a large number of records it is better to delete these in chunks
so that we do not create large transaction on which are time consuming on
Postgres e.g. the following script deletes the revision data for a model
called Model
in the app app
, a day at a time
day=365
while [ $day -gt 0 ]; do
day=`expr $day - 1`
echo "Deleting reversion older than $day days"
django-admin deleterevisions app.Model --days=$day
done
This will split the task into smaller chunks.
Once the data is deleted you can then remove the reversion.register()
line
from the models module.
Tip
If you want to delete all revisions, run the deleterevisions
management command without the model parameter.
Testing
To check the number of Version
records created:
import reversion
qs = reversion.models.Version.objects.all()
assert 0 == qs.count()
To filter on Version
for a model:
pks = [
x.pk
for x in reversion.models.Version.objects.get_for_model(UserConsent)
]