From 3623812ab4e6c74fcbe68453325d7638700d0570 Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Fri, 15 May 2015 15:14:57 +0200 Subject: [PATCH] Some work on m2m relationships --- src/auditlog/models.py | 18 ++++++++++++++++++ src/auditlog_tests/models.py | 3 +++ src/auditlog_tests/tests.py | 16 +++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/auditlog/models.py b/src/auditlog/models.py index ad0184b..4d5930d 100644 --- a/src/auditlog/models.py +++ b/src/auditlog/models.py @@ -6,6 +6,7 @@ from django.conf import settings from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models +from django.db.models import QuerySet, Q from django.utils.encoding import python_2_unicode_compatible, smart_text from django.utils.six import iteritems, integer_types from django.utils.translation import ugettext_lazy as _ @@ -59,6 +60,23 @@ class LogEntryManager(models.Manager): else: return self.filter(content_type=content_type, object_pk=pk) + def get_for_objects(self, queryset): + """ + Get log entries for the objects in the specified queryset. + + :param queryset: The queryset to get the log entries for. + :type queryset: QuerySet + :return: The LogEntry objects for the objects in the given queryset. + :rtype: QuerySet + """ + if not isinstance(queryset, QuerySet) or queryset.count() == 0: + return self.none() + + content_type = ContentType.objects.get_for_model(queryset.model) + primary_keys = queryset.values_list(queryset.model._meta.pk.name, flat=True) + + return self.filter(content_type=content_type).filter(Q(object_id__in=primary_keys) | Q(object_pk__in=primary_keys)) + def get_for_model(self, model): """ Get log entries for all objects of a specified type. diff --git a/src/auditlog_tests/models.py b/src/auditlog_tests/models.py index 9a05d26..4d554a4 100644 --- a/src/auditlog_tests/models.py +++ b/src/auditlog_tests/models.py @@ -85,5 +85,8 @@ class SimpleExcludeModel(models.Model): auditlog.register(SimpleModel) auditlog.register(AltPrimaryKeyModel) auditlog.register(ProxyModel) +auditlog.register(RelatedModel) +auditlog.register(ManyRelatedModel) +auditlog.register(ManyRelatedModel.related.through) auditlog.register(SimpleIncludeModel, include_fields=['label', ]) auditlog.register(SimpleExcludeModel, exclude_fields=['text', ]) diff --git a/src/auditlog_tests/tests.py b/src/auditlog_tests/tests.py index cd93bd3..02ae9fa 100644 --- a/src/auditlog_tests/tests.py +++ b/src/auditlog_tests/tests.py @@ -7,7 +7,7 @@ from django.test import TestCase, RequestFactory from auditlog.middleware import AuditlogMiddleware from auditlog.models import LogEntry from auditlog_tests.models import SimpleModel, AltPrimaryKeyModel, ProxyModel, \ - SimpleIncludeModel, SimpleExcludeModel + SimpleIncludeModel, SimpleExcludeModel, RelatedModel, ManyRelatedModel class SimpleModelTest(TestCase): @@ -75,6 +75,20 @@ class ProxyModelTest(SimpleModelTest): self.obj = ProxyModel.objects.create(text='I am not what you think.') +class ManyRelatedModelTest(TestCase): + """ + Test the behaviour of a many-to-many relationship. + """ + def setUp(self): + self.obj = ManyRelatedModel.objects.create() + self.rel_obj = ManyRelatedModel.objects.create() + self.obj.related.add(self.rel_obj) + + def test_related(self): + self.assertEqual(LogEntry.objects.get_for_objects(self.obj.related.all()).count(), self.rel_obj.history.count()) + self.assertEqual(LogEntry.objects.get_for_objects(self.obj.related.all()).first(), self.rel_obj.history.first()) + + class MiddlewareTest(TestCase): """ Test the middleware responsible for connecting and disconnecting the signals used in automatic logging.