Skip to content

Commit 03e05bc

Browse files
authored
Merge pull request #86 from morlandi/master
Customizable list filters for ModelAdmins (revised). Closes #52.
2 parents 5249423 + 15ccd16 commit 03e05bc

File tree

8 files changed

+77
-10
lines changed

8 files changed

+77
-10
lines changed

README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,37 @@ Below are some of the settings you may want to use. These should be defined in y
5959
will be matched against the URL path.
6060
[Check our wiki](https://github.com/soynatan/django-easy-audit/wiki/Settings#request-auditing)
6161
for more details on how to use it.
62-
62+
6363
* `DJANGO_EASY_AUDIT_CRUD_DIFFERENCE_CALLBACKS`
6464

6565
May point to a list of callables/string-paths-to-functions-classes in which the application code can determine
6666
on a per CRUDEvent whether or not the application chooses to create the CRUDEvent or not. This is different
67-
from the registered/unregistered settings (e.g. `DJANGO_EASY_AUDIT_UNREGISTERED_CLASSES_EXTRA`).
67+
from the registered/unregistered settings (e.g. `DJANGO_EASY_AUDIT_UNREGISTERED_CLASSES_EXTRA`).
6868
This is meant to be for dynamic configurations where the application
6969
may inspect the current save/create/delete and choose whether or not to save that into the database or ignore it.
70-
70+
7171
* `DJANGO_EASY_AUDIT_USER_DB_CONSTRAINT`
7272

73-
Default is `True`. This is reserved for future use (does not do anything yet). The functionality provided by the
74-
setting (whether enabled or disabled) could be handled more explicitly in certain
73+
Default is `True`. This is reserved for future use (does not do anything yet). The functionality provided by the
74+
setting (whether enabled or disabled) could be handled more explicitly in certain
7575
code paths (or even internally as custom model managers). For projects that separate the easyaudit database, such
7676
that the tables are not on the same database as the user table, this could help with making certain queries easier.
7777
Again, this doesn't do anything yet, and if it ever does, the version will be increased and the README will be
7878
updated accordingly. If you keep your database together (the standard usage), you have nothing to worry about.
7979

80+
* `DJANGO_EASY_AUDIT_CRUD_EVENT_LIST_FILTER`
81+
82+
* `DJANGO_EASY_AUDIT_LOGIN_EVENT_LIST_FILTER`
83+
84+
* `DJANGO_EASY_AUDIT_REQUEST_EVENT_LIST_FILTER`
85+
86+
Changeview filters configuration.
87+
Used to remove filters when the corresponding list of data would be too long.
88+
Defaults are:
89+
- ['event_type', 'content_type', 'user', 'datetime', ] for CRUDEventAdmin
90+
- ['login_type', 'user', 'datetime', ] for LoginEventAdmin
91+
- ['method', 'user', 'datetime', ] for RequestEventAdmin
92+
8093
## What does it do
8194

8295
Django Easy Audit uses [Django signals](https://docs.djangoproject.com/en/dev/topics/signals/)

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ Quick start
2323

2424
3. Run 'python manage.py migrate easyaudit' to create the audit models.
2525

26-
4. That's it! Now every CRUD event on your whole project will be registered in the audit models, which you will be able to query from the Django admin app. Additionally, this app will also log all authentication events and all URLs requested.
26+
4. That's it! Now every CRUD event on your whole project will be registered in the audit models, which you will be able to query from the Django admin app. Additionally, this app will also log all authentication events and all URLs requested.

easyaudit/admin.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
from . import settings
1010
from .models import CRUDEvent, LoginEvent, RequestEvent
1111
from .admin_helpers import prettify_json, EasyAuditModelAdmin
12+
from .settings import CRUD_EVENT_LIST_FILTER, LOGIN_EVENT_LIST_FILTER, REQUEST_EVENT_LIST_FILTER
1213

1314

1415
# CRUD events
1516
class CRUDEventAdmin(EasyAuditModelAdmin):
1617
list_display = ['get_event_type_display', 'content_type', 'object_id', 'object_repr_link', 'user_link', 'datetime']
1718
date_hierarchy = 'datetime'
18-
list_filter = ['event_type', 'content_type', 'user', 'datetime', ]
19+
list_filter = CRUD_EVENT_LIST_FILTER
1920
search_fields = ['=object_id', 'object_json_repr', ]
2021
readonly_fields = ['event_type', 'object_id', 'content_type',
2122
'object_repr', 'object_json_repr_prettified', 'user',
@@ -57,7 +58,7 @@ def changed_fields_prettified(self, obj):
5758
class LoginEventAdmin(EasyAuditModelAdmin):
5859
list_display = ['datetime', 'get_login_type_display', 'user_link', 'username', 'remote_ip']
5960
date_hierarchy = 'datetime'
60-
list_filter = ['login_type', 'user', 'datetime', ]
61+
list_filter = LOGIN_EVENT_LIST_FILTER
6162
search_fields = ['=remote_ip', 'username', ]
6263
readonly_fields = ['login_type', 'username', 'user', 'remote_ip', 'datetime', ]
6364

@@ -70,7 +71,7 @@ class LoginEventAdmin(EasyAuditModelAdmin):
7071
class RequestEventAdmin(EasyAuditModelAdmin):
7172
list_display = ['datetime', 'user_link', 'method', 'url', 'remote_ip']
7273
date_hierarchy = 'datetime'
73-
list_filter = ['method', 'user', 'datetime', ]
74+
list_filter = REQUEST_EVENT_LIST_FILTER
7475
search_fields = ['=remote_ip', 'username', 'url', 'query_string', ]
7576
readonly_fields = ['url', 'method', 'query_string', 'user', 'remote_ip', 'datetime', ]
7677

easyaudit/settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ def get_model_list(class_list):
9898
# model.objects.all().delete()
9999
# which is however much costly when many rows are involved
100100
TRUNCATE_TABLE_SQL_STATEMENT = getattr(settings, 'DJANGO_EASY_AUDIT_TRUNCATE_TABLE_SQL_STATEMENT', '')
101+
102+
# Changeview filters configuration
103+
CRUD_EVENT_LIST_FILTER = getattr(settings, 'DJANGO_EASY_AUDIT_CRUD_EVENT_LIST_FILTER', ['event_type', 'content_type', 'user', 'datetime', ])
104+
LOGIN_EVENT_LIST_FILTER = getattr(settings, 'DJANGO_EASY_AUDIT_LOGIN_EVENT_LIST_FILTER', ['login_type', 'user', 'datetime', ])
105+
REQUEST_EVENT_LIST_FILTER = getattr(settings, 'DJANGO_EASY_AUDIT_REQUEST_EVENT_LIST_FILTER', ['method', 'user', 'datetime', ])

easyaudit/tests/test_app/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ class TestModel(models.Model):
77

88
class TestForeignKey(models.Model):
99
name = models.CharField(max_length=50)
10-
test_fk = models.ForeignKey(TestModel)
10+
test_fk = models.ForeignKey(TestModel, on_delete=models.CASCADE)
11+
1112

1213
class TestM2M(models.Model):
1314
name = models.CharField(max_length=50)

easyaudit/tests/test_app/tests.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22
import json
3+
import re
34
from django.test import TestCase
45
try: # Django 2.0
56
from django.urls import reverse
@@ -14,6 +15,9 @@
1415

1516
TEST_USER_EMAIL = '[email protected]'
1617
TEST_USER_PASSWORD = 'password'
18+
TEST_ADMIN_EMAIL = '[email protected]'
19+
TEST_ADMIN_PASSWORD = 'password'
20+
1721

1822
class TestAuditModels(TestCase):
1923

@@ -93,3 +97,43 @@ def test_manual_set_user(self):
9397
self.assertEqual(crud_event_qs.count(), 1)
9498
crud_event = crud_event_qs[0]
9599
self.assertEqual(crud_event.user, None)
100+
101+
102+
class TestAuditAdmin(TestCase):
103+
104+
def _setup_superuser(self, email, password):
105+
admin = User.objects.create_superuser(email, email, TEST_ADMIN_PASSWORD)
106+
admin.save()
107+
return admin
108+
109+
def _log_in_user(self, email, password):
110+
login = self.client.login(username=email, password=password)
111+
self.assertTrue(login)
112+
113+
def _list_filters(self, content):
114+
"""
115+
Extract filters from response content;
116+
example:
117+
118+
<div id="changelist-filter">
119+
<h2>Filter</h2>
120+
<h3> By method </h3>
121+
...
122+
<h3> By datetime </h3>
123+
...
124+
</div>
125+
126+
returns:
127+
['method', 'datetime', ]
128+
"""
129+
html = re.search('<div\s*id="changelist-filter">(.*?)</div>', str(content)).group(0)
130+
filters = re.findall('<h3>\s*By\s*(.*?)\s*</h3>', html)
131+
return filters
132+
133+
def test_request_event_admin_no_users(self):
134+
self._setup_superuser(TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD)
135+
self._log_in_user(TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD)
136+
response = self.client.get(reverse('admin:easyaudit_requestevent_changelist'))
137+
self.assertEqual(200, response.status_code)
138+
filters = self._list_filters(response.content)
139+
print(filters)

easyaudit/tests/test_app/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.conf.urls import url
22
from test_app import views
33

4+
app_name = 'test_easyaudit'
45

56
urlpatterns = [
67
url("create-obj", views.create_obj_view, name="create-obj"),

easyaudit/tests/test_project/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,5 @@
121121
# https://docs.djangoproject.com/en/1.11/howto/static-files/
122122

123123
STATIC_URL = '/static/'
124+
125+
DJANGO_EASY_AUDIT_REQUEST_EVENT_LIST_FILTER = ['method', 'datetime', ]

0 commit comments

Comments
 (0)