Django Reversion **************** .. highlight:: python .. 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 .. code-block:: bash 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 -c "select relname, relpages from pg_class order by relpages desc;" | grep "reversion_"jk A more detailed breakdown can be obtained using .. code-block:: sql psql -U postgres -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" > /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: .. code-block:: bash django-admin deleterevisions . 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 .. code-block:: bash 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) ] .. _manual: https://django-reversion.readthedocs.io/en/stable/index.html