# Log and Visualize User Action History in Django

> Build a UserAction model to log events like logins and password changes, then query and chart the results, or use django-simple-history instead

**URL:** https://sentry.io/answers/log-and-visualize-user-action-history-in-django/

---

## The Problem

I am building a web application using Django and want to monitor user actions such as logins, password changes, and profile updates – basically any action a user can take in my app. I would then like to query this information and get statistics and visualizations from it, for example, a graph showing monthly logins, or weekly profile updates. How should I go about doing this?

## The Solution

We can log user actions in Django by building and using a new `UserAction` model. First, we'll create the model as below:

```python
from django.db import models
from django.contrib.auth.models import User

class UserAction(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    action = models.CharField(max_length=255)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.user.username} {self.action} at {self.timestamp}'
```

We've included a reference to the user, a string for the action, and a timestamp. Depending on your application's needs, you may require additional fields.

Next, we need a function to create log entries for user actions, like the one below:

```python
def log_user_action(user, action):
    UserAction.objects.create(user=user, action=action)
```

Finally, we can call this function in our views or signals, whenever an action has been taken.

```python
# After a user logs in:
log_user_action(request.user, 'login')

# After a user changes their password:
log_user_action(request.user, 'password change')
```

All user actions we record with this logging function will now be stored as records in our database, and we can query them in the same way we would query any Django model. For example, we could write this function to return the count of a given action taken by one or all users over a specified period (defaulting to one month):

```python
from django.utils import timezone
from dateutil.relativedelta import relativedelta

def user_action_count(action, days=30, user=None):
    start_date = timezone.now() - relativedelta(days=days)
    if user: # actions by one user
        return UserAction.objects.filter(user=user, action=action, timestamp__gte=start_date).count()
    else: # actions by all users
        return UserAction.objects.filter(action=action, timestamp__gte=start_date).count()
```

We could then call this function as follows:

```python
# Get all user logins for the month
logins = user_action_count('login')
# Get all user password changes for the quarter
password_changes = user_action_count('password change', 90)
# Get all profile changes of the logged in user for the week
profile_changes = user_action_count('profile change', 7, request.user)
```

We can then use this data in our views either directly or in graphs built with common data visualization libraries such as [Chart.js](https://www.chartjs.org/) or [D3.js](https://d3js.org/).

As an alternative to writing this functionality ourselves, we could achieve this functionality using an open-source library such as [`django-easy-audit`](https://pypi.org/project/django-easy-audit/) or [`django-simple-history`](https://pypi.org/project/django-simple-history/). The `django-easy-audit` library is the simplest to set up and will automatically start logging every create, read, delete, and update on every model in your project, as well as authentication events and URL requests. The `django-simple-history` library requires a bit more setup but allows you to be more selective about which models and actions you track.

Django also includes built-in action logging as part of its [admin site](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/) to log actions taken by admins using `LogEntry` objects. While this can be used outside the admin panel, it's considered a private API and changes to its functionality for Django 5 have not been officially documented as of this writing. For this reason, and to avoid mixing user action logs with admin action logs, we don't recommend implementing this functionality using `LogEntry` objects.

---

*Source: [sentry.io/answers/log-and-visualize-user-action-history-in-django/](https://sentry.io/answers/log-and-visualize-user-action-history-in-django/)*
