Bitbucket is a code hosting site with unlimited public and private repositories. We're also free for small teams!

Close

Django Audit

A quick and simple app for providing standard audit fields without the typical inheritance.

Backstory

As of September 2012, it appears that there is still no clear standard for implementing audit data or trails in Django. I created this app because I needed an audit tool that provided the most common fields, but I did not want or need history or revision tracking.

In addition to the basic audit fields, I also wanted a tool that did not require me to implement auditing in advance, as when inheriting fields from an abstract model. There were a couple of reasons for this:

  1. Auditing and audit fields, though common, is not always wanted or needed, and even when audit fields are required, the choice of implementation should rest with the developer.
  2. I often produce small and re-usable Django apps where I prefer to have few or no dependencies, and adding audit fields not only adds a dependency, but also violates the first principal above.

Implementation

Model Audit approaches auditing as simply as possible, but does take a slightly different approach than other packages.

Models

Two, standard models are implemented:

  1. TimeAudit for added/modified timestamps.
  2. UserAudit for added/modified by user data.

These models are independent of the rest of the data schema and are connected to Django's content types.

API

There are two API functions that correspond to each of the models:

  1. time_audit for recording timestamps. added/modified timestamps.
  2. user_audit for user data.

Mixins

Finally, there are two mixins that provide easy, but optional access to the audit data.

  1. TimeAuditMixin gives access to added_date_time, modified_date_time and the TimeAudit instance via the time_audit() method.
  2. UserAuditMixin gives access to added_by, modified_by and the UserAudit instance via the user_audit() method.

Usage

Minimal

The simplest possible implementation involves using the time_audit and user_audit API in your views, or in the save_model() method of your model admin:

from model_audit.api import time_audit, user_audit

class MyModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.save()
        time_audit(request.user, obj)
        user_audit(request.user, obj)

Advanced

The minimal implementation is easy and straight-forward, but what if you want to access an audit property directly from your model? The mixins allow you to do this:

from model_audit.models import UserAuditMixin, TimeAuditMixin

class MyModel(UserAuditMixin, TimeAuditMixin):
    # ...

Then to access added_by simply call:

added_by = MyModelInstance.added_by

Note: In this implementation, each call to a method will result in a database query, which may become a performance issue under heavy use. This may be reduced a little by calling the time_audit() or user_audit() methods, and then calling the property:

UserAuditInstance = MyModelInstance.user_audit()

Even so, performance might still be a problem in a large system.

Generic Relations

One might also implement generic relations to access the related data.

Limitations

Model Audit does come with some limitations.

  1. Performance: As mentioned under advanced usage above, slow performance is a possibility for a system under heavy use with lots of audit data. In this case, inheritance from an abstract class that provides the desired fields becomes much more desirable and should be part of the planning and engineering process.
  2. History: The purpose of the app is to provide audit fields, but not historical data or revisions.
  3. Existing Records: If records already exist, the "added" audit data will be incorrect. It is best to start a new app using Model Audit in the first place or set this data in advance of Model Audit adoption.

To-do

A few ideas for improvement:

  • Admin access: Implement standard model admin for audit data. Everything would be read-only?
  • Log output: Provide a view which generates log-like output. Perhaps with an export option?
  • Unit tests: What meaningful testing could be implemented to insure flawless operation?

Recent activity

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.