Django Timeline Logger works by using a custom model TimelineLog, which is designed to store:

  • A Django model instance (a database object).
  • A timestamp.
  • A user instance (optional).
  • A path to a template (optional, defaults to timeline_logger/default.txt).
  • A context (optional).

Given those details, it’s pretty clear how it works: whenever you want to log an event in your system, you create a TimelineLog for it, passing the data you consider useful in the context and using a template to render the message.

The context is stored in a django.contrib.postgres.JSONField, which basically accepts a Python dictionary representing JSON data, to be built by you with the data you want to pass to the message template.

Default example

An example of a default usage of the TimelineLog model could be as follows. Imagine you have a “blog” application where your users can create posts, stored by using a Django model Post.

Using the default behaviour of TimelineLog, you can create a log each time a user posts a new entry in the blog, like this:

from timeline_logger.models import TimelineLog

# Whatever logic you have before creating the post entry.

post = Post.objects.create(
    title='New blog entry',

log = TimelineLog.objects.create(

There you go. A new timeline entry has been created to record the event that a user posted a new blog entry.

You can then see the default message for such event by calling the TimelineLog.get_message() method:


That function will return a text string, like this one:

'July 1, 2016, 9:08 a.m. - Anonymous user event on New blog entry\n'

With all this in place, you can now access the view included with the Django Timeline Logger package: http://localhost:8000/timeline to see a paginated list of your event logs.

Custom messages using templates and context

Of course, you want to have your own custom messages for each different event you want to track, maybe showing in the log as more data as possible. You can easily do that by using regular Django templates in your TimelineLog instances.

Let’s see an example of usage. Imagine you have a web shop and you want to log user purchases of certain items, whatever the item is. In this scenario, you could have a view to handle a user form submission representing a purchase. You should be able to log each purchase with any details you want by doing something like this:

from django.views.generic import CreateView

from timeline_logger.models import TimelineLog

from my_app.models import Invoice, Item

class PurchaseView(CreateView):
    """ Manages a client purchase and creates the invoice """
    model = Invoice

    def post(self, request, *args, **kwargs):
        response = super(PurchaseView, self).post(request, *args, **kwargs)

        # The sold item.
        item = Item.objects.get(pk=kwargs['item'])

        # Add some extra data to the log message.
        extra_data = {'invoice': self.object}

        # Log the purchase event.

        return response

You logged there the “purchase event”, passing the request object, using a custom template to render your own message and some context for it. A simple template you can write in your my_app/templates/timeline_logger directory could look like this:

{% load i18n %}
{% blocktrans trimmed with timestamp=log.timestamp user=log.user|default:_('Anonymous user') object=log.content_object extra=log.exta_data|safe %}
   {{ timestamp }} - {{ user }} purchased item "{{ object }}", using payment method "{{ extra.invoice.method }}", for a total price of {{ }} €.
{% endblocktrans %}

So, in your http://localhost:8000/timeline view, this log entry will appear more or less as follows:

July 4, 2016, 8:13 a.m. - John Doe purchased item “Nescafé Dolce Gusto”, using payment method “PayPal”, for a total price of 35 €.

Log from requests

Probably you’ll better like to log events based on user requests, like for example a user comment in a blog post, a form submission, a click in a “like” button or a purchase in your web shop.

You can easily do so by using the TimelineLog.log_from_request method, which accepts a Django HTTPRequest object (accessible in all Django views via the request parameter or the self.request view class attribute) and a Django model instance, plus an optional template and its context.

In our previous example, we can substitute the TimelineLog.objects.create(... part by this:


And the resulting log instance and message will be the same.

Django-import-export integration

Django-timeline-logger ships with a ModelResource:

   from timeline_logger.resources import TimelineLogResource


It's not enabled in the default admin, as django-import-export is an
optional dependency.