# django-reversion API

Use the django-reversion API to build version-controlled apps. See also Views and Middleware.

## Overview

### Registering models

Models must be registered with django-reversion before they can be used with the API.

    from django.db import models
    import reversion

    @reversion.register()
    class YourModel(models.Model):

        pass

Hint

If you’re using the Admin integration, model registration is automatic. If you’re using django-reversion in a management command, make sure you call `django.contrib.admin.autodiscover()` to load the admin modules before using the django-reversion API.

Hint

Whenever you register a model with django-reversion, run createinitialrevisions.

### Creating revisions

A revision represents one or more changes made to your model instances, grouped together as a single unit. You create a revision by creating a revision block. When you call `save()` on a registered model inside a revision block, it will be added to that revision.

    # Declare a revision block.
    with reversion.create_revision():

        # Save a new model instance.
        obj = YourModel()
        obj.name = "obj v1"
        obj.save()

        # Store some meta-information.
        reversion.set_user(request.user)
        reversion.set_comment("Created revision 1")

    # Declare a new revision block.
    with reversion.create_revision():

        # Update the model instance.
        obj.name = "obj v2"
        obj.save()

        # Store some meta-information.
        reversion.set_user(request.user)
        reversion.set_comment("Created revision 2")

Important

Bulk actions, such as `Queryset.update()`, do not send signals, so won’t be noticed by django-reversion.

### Loading revisions

Each model instance saved in a revision block is serialized as a reversion.models.Version. All versions in a revision block are associated with a single reversion.models.Revision.

You can load a reversion.models.VersionQuerySet of versions from the database. Versions are loaded with the most recent version first.

    from reversion.models import Version

    # Load a queryset of versions for a specific model instance.
    versions = Version.objects.get_for_object(instance)
    assert len(versions) == 2

    # Check the serialized data for the first version.
    assert versions[1].field_dict["name"] == "obj v1"

    # Check the serialized data for the second version.
    assert versions[0].field_dict["name"] == "obj v2"

### Revision metadata

reversion.models.Revision stores meta-information about the revision.

    # Check the revision metadata for the first revision.
    assert versions[1].revision.comment == "Created revision 1"
    assert versions[1].revision.user == request.user
    assert isinstance(versions[1].revision.date_created, datetime.datetime)

    # Check the revision metadata for the second revision.
    assert versions[0].revision.comment == "Created revision 2"
    assert versions[0].revision.user == request.user
    assert isinstance(versions[0].revision.date_created, datetime.datetime)

### Reverting revisions

Revert a reversion.models.Revision to restore the serialized model instances.

    # Revert the first revision.
    versions[1].revision.revert()

    # Check the model instance has been reverted.
    obj.refresh_from_db()
    assert obj.name == "version 1"

    # Revert the second revision.
    versions[0].revision.revert()

    # Check the model instance has been reverted.
    obj.refresh_from_db()
    assert obj.name == "version 2"

### Restoring deleted model instances

Reverting a reversion.models.Revision will restore any serialized model instances that have been deleted.

    # Delete the model instance, but store the pk.
    pk = obj.pk
    obj.delete()

    # Revert the second revision.
    versions[0].revision.revert()

    # Check the model has been restored to the database.
    obj = YourModel.objects.get(pk=obj.pk)
    assert obj.name == "version 2"

## Registration API

`reversion.register(model, **options)`

> Registers a model with django-reversion.

> Throws reversion.RegistrationError if the model has already been registered.

> `model`

>   The Django model to register.

> `fields=None`

>   An iterable of field names to include in the serialized data. If `None`, all fields will be included.

> `exclude=()`

>   An iterable of field names to exclude from the serialized data.

> `follow=()`

>   An iterable of model relationships to follow when saving a version of this model. `ForeignKey`, `ManyToManyField` and reversion `ForeignKey` relationships are supported. Any property that returns a `Model` or `QuerySet` is also supported.

> `format="json"`

>   The name of a Django serialization format to use when saving the model instance.

> `for_concrete_model=True`

>   If `True` proxy models will be saved under the same content type as their concrete model. If `False`, proxy models will be saved under their own content type, effectively giving proxy models their own distinct history.

> `ignore_duplicates=False`

>   If `True`, then an additional check is performed to avoid saving duplicate versions for this model.

>   Checking for duplicate revisions adds significant overhead to the process of creating a revision. Don’t enable it unless you really need it!

> `use_natural_foreign_keys=False`

>   If `True`, the the model will be serialized using natural keys.

>   See Serialization of natural keys

> Hint

> By default, django-reversion will not register any parent classes of a model that uses multi-table inheritance. If you wish to also add parent models to your revision, you must explicitly add their `parent_ptr` fields to the `follow` parameter when you register the model.

> Hint

> Whenever you register a model with django-reversion, run createinitialrevisions.

`reversion.is_registered(model)`

> Returns whether the given model has been registered with django-reversion.

> `model`

>   The Django model to check.

`reversion.unregister(model)`

> Unregisters the given model from django-reversion.

> Throws reversion.RegistrationError if the model has not been registered with django-reversion.

> `model`

>   The Django model to unregister.

`reversion.get_registered_models()`

> Returns an iterable of all registered models.

## Revision API

`reversion.create_revision(manage_manually=False, using=None, atomic=True)`

> Marks a block of code as a revision block. Can also be used as a decorator.

> `manage_manually`

>   If `True`, versions will not be saved when a model’s `save()` method is called. This allows version control to be switched off for a given revision block.

> `using`

>   The database to save the revision data. The revision block will be wrapped in a transaction using this database. If `None`, the default database for reversion.models.Revision will be used.

> `atomic`

>   If `True`, the revision block will be wrapped in a `transaction.atomic()`.

`reversion.is_active()`

> Returns whether there is currently an active revision block.

`reversion.is_manage_manually()`

> Returns whether the current revision block is in `manage_manually` mode.

`reversion.set_user(user)`

> Sets the user for the current revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

> `user`

>   A `User` model instance (or whatever your `settings.AUTH_USER_MODEL` is).

`reversion.get_user()`

> Returns the user for the current revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

`reversion.set_comment(comment)`

> Sets the comment for the current revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

> `comment`

>   The text comment for the revision.

`reversion.get_comment()`

> Returns the comment for the current revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

`reversion.set_date_created(date_created)`

> Sets the creation date for the current revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

> `date_created`

>   The creation date for the revision.

`reversion.get_date_created()`

> Returns the creation date for the current revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

`reversion.add_meta(model, **values)`

> Adds custom metadata to a revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

> `model`

>   A Django model to store the custom metadata. The model must have a `ForeignKey` or `OneToOneField` to reversion.models.Revision.

> `**values`

>   Values to be stored on `model` when it is saved.

`reversion.add_to_revision(obj, model_db=None)`

> Adds a model instance to a revision.

> Throws reversion.RevisionManagementError if there is no active revision block.

> `obj`

>   A model instance to add to the revision.

> `model_db`

>   The database where the model is saved. Defaults to the default database for the model.

## reversion.models.VersionQuerySet

A `QuerySet` of reversion.models.Version. The results are ordered with the most recent reversion.models.Version first.

`Version.objects.get_for_model(model, model_db=None)`

> Returns a reversion.models.VersionQuerySet for the given model.

> Throws reversion.RegistrationError if the model has not been registered with django-reversion.

> `model`

>   A registered model.

> `model_db`

>   The database where the model is saved. Defaults to the default database for the model.

`Version.objects.get_for_object(obj, model_db=None)`

> Returns a reversion.models.VersionQuerySet for the given model instance.

> Throws reversion.RegistrationError if the model has not been registered with django-reversion.

> `obj`

>   An instance of a registered model.

> `model_db`

>   The database where the model is saved. Defaults to the default database for the model.

`Version.objects.get_for_object_reference(model, pk, model_db=None)`

> Returns a reversion.models.VersionQuerySet for the given model and primary key.

> Throws reversion.RegistrationError if the model has not been registered with django-reversion.

> `model`

>   A registered model.

> `pk`

>   The database primary key of a model instance.

> `model_db`

>   The database where the model is saved. Defaults to the default database for the model.

`Version.objects.get_deleted(model, model_db=None)`

> Returns a reversion.models.VersionQuerySet for the given model containing versions where the serialized model no longer exists in the database.

> Throws reversion.RegistrationError if the model has not been registered with django-reversion.

> `model`

>   A registered model.

> `db`

>   The database to load the versions from.

> `model_db`

>   The database where the model is saved. Defaults to the default database for the model.

`Version.objects.get_unique()`

> Returns an iterable of reversion.models.Version, where each version is unique for a given database, model instance, and set of serialized fields.

## reversion.models.Version

Represents a single model instance serialized in a revision.

`Version.id`

> The database primary key of the reversion.models.Version.

`Version.revision`

> A `ForeignKey` to a reversion.models.Revision instance.

`Version.content_type`

> The `ContentType` of the serialized model instance.

`Version.object_id`

> The string representation of the serialized model instance’s primary key.

`Version.db`

> The Django database alias where the serialized model was saved.

`Version.format`

> The name of the Django serialization format used to serialize the model instance.

`Version.serialized_data`

> The raw serialized data of the model instance.

`Version.object_repr`

> The stored snapshot of the model instance’s `__str__` method when the instance was serialized.

`Version.field_dict`

> A dictionary of stored model fields. This includes fields from any parent models in the same revision.

> Throws reversion.RevertError if the model could not be deserialized or reverted, e.g. the serialized data is not compatible with the current database schema.

`Version.revert()`

> Restores the serialized model instance to the database. To restore the entire revision, use Revision.revert().

> Throws reversion.RevertError if the model could not be deserialized or reverted, e.g. the serialized data is not compatible with the current database schema.

## reversion.models.Revision

Contains metadata about a revision, and groups together all reversion.models.Version instances created in that revision.

`Revision.id`

> The database primary key of the reversion.models.Revision.

`Revision.date_created`

> A `datetime` when the revision was created.

`Revision.user`

> The `User` that created the revision, or None.

`Revision.get_comment()`

> A text comment on the revision.

`Revision.revert(delete=False)`

> Restores all contained serialized model instances to the database.

> Throws reversion.RevertError if the model could not be deserialized or reverted, e.g. the serialized data is not compatible with the current database schema.

> `delete`

>   If `True`, any model instances which have been created and are reachable by the `follow` clause of any model instances in this revision will be deleted. This effectively restores a group of related models to the state they were in when the revision was created.