Code

Ticket #2901: admin_log_with_site.2.diff

File admin_log_with_site.2.diff, 10.0 KB (added by Christopher Lenz <cmlenz@…>, 8 years ago)

Fixed patch, previous one didn't correctly filter the template tag output

Line 
1Index: django/views/defaults.py
2===================================================================
3--- django/views/defaults.py    (revision 3900)
4+++ django/views/defaults.py    (working copy)
5@@ -24,33 +24,12 @@
6     if absurl.startswith('http://'):
7         return http.HttpResponseRedirect(absurl)
8 
9+    # Try to figure out the related site for the object
10     object_domain = None
11+    site = Site.objects.get_for_obj(obj)
12+    if site:
13+        object_domain = site.domain
14 
15-    # Otherwise, we need to introspect the object's relationships for a
16-    # relation to the Site object
17-    opts = obj._meta
18-
19-    # First, look for an many-to-many relationship to sites
20-    for field in opts.many_to_many:
21-        if field.rel.to is Site:
22-            try:
23-                object_domain = getattr(obj, field.name).all()[0].domain
24-            except IndexError:
25-                pass
26-            if object_domain is not None:
27-                break
28-
29-    # Next look for a many-to-one relationship to site
30-    if object_domain is None:
31-        for field in obj._meta.fields:
32-            if field.rel and field.rel.to is Site:
33-                try:
34-                    object_domain = getattr(obj, field.name).domain
35-                except Site.DoesNotExist:
36-                    pass
37-                if object_domain is not None:
38-                    break
39-
40     # Fall back to the current site (if possible)
41     if object_domain is None:
42         try:
43Index: django/contrib/sites/models.py
44===================================================================
45--- django/contrib/sites/models.py      (revision 3900)
46+++ django/contrib/sites/models.py      (working copy)
47@@ -2,10 +2,35 @@
48 from django.utils.translation import gettext_lazy as _
49 
50 class SiteManager(models.Manager):
51+
52     def get_current(self):
53         from django.conf import settings
54         return self.get(pk=settings.SITE_ID)
55 
56+    def get_for_object(self, obj):
57+        """
58+        Returns the Site object for the given model object, if that object has
59+        a corresponding relation. Otherwise it returns None.
60+        """
61+        opts = obj._meta
62+
63+        # First, look for an many-to-many relationship to sites
64+        for field in opts.many_to_many:
65+            if field.rel.to is Site:
66+                if getattr(obj, field.name):
67+                    try:
68+                        return getattr(obj, field.name).all()[0]
69+                    except IndexError:
70+                        pass
71+
72+        # Next look for a many-to-one relationship to sites
73+        for field in obj._meta.fields:
74+            if field.rel and field.rel.to is Site:
75+                return getattr(obj, field.name)
76+
77+        # Cannot determine a direct relation to sites, so return None
78+        return None
79+
80 class Site(models.Model):
81     domain = models.CharField(_('domain name'), maxlength=100)
82     name = models.CharField(_('display name'), maxlength=50)
83Index: django/contrib/admin/templatetags/log.py
84===================================================================
85--- django/contrib/admin/templatetags/log.py    (revision 3900)
86+++ django/contrib/admin/templatetags/log.py    (working copy)
87@@ -1,11 +1,16 @@
88 from django import template
89+from django.conf import settings
90 from django.contrib.admin.models import LogEntry
91+from django.db import models
92 
93 register = template.Library()
94 
95 class AdminLogNode(template.Node):
96-    def __init__(self, limit, varname, user):
97-        self.limit, self.varname, self.user = limit, varname, user
98+    def __init__(self, limit, varname, user, site):
99+        self.limit = limit
100+        self.varname = varname
101+        self.user = user
102+        self.site = site
103 
104     def __repr__(self):
105         return "<GetAdminLog Node>"
106@@ -13,7 +18,15 @@
107     def render(self, context):
108         if self.user is not None and not self.user.isdigit():
109             self.user = context[self.user].id
110-        context[self.varname] = LogEntry.objects.filter(user__id__exact=self.user).select_related()[:self.limit]
111+
112+        entries = LogEntry.objects.filter(user__id__exact=self.user)
113+        if self.site:
114+            if not self.site.isdigit():
115+                self.site = context[self.site].id
116+            entries = entries.filter(models.Q(site__id=self.site) |
117+                                     models.Q(site__id__isnull=True))
118+
119+        context[self.varname] = entries.select_related()[:self.limit]
120         return ''
121 
122 class DoGetAdminLog:
123@@ -23,16 +36,24 @@
124     Usage::
125 
126         {% get_admin_log [limit] as [varname] for_user [context_var_containing_user_obj] %}
127+       
128+    or::
129 
130+        {% get_admin_log [limit] as [varname] for_site [context_var_containing_site_obj] %}
131+
132     Examples::
133 
134         {% get_admin_log 10 as admin_log for_user 23 %}
135-        {% get_admin_log 10 as admin_log for_user user %}
136+        {% get_admin_log 10 as admin_log for_user varname %}
137+        {% get_admin_log 10 as admin_log for_site %}
138+        {% get_admin_log 10 as admin_log for_site 2 %}
139+        {% get_admin_log 10 as admin_log for_site varname %}
140         {% get_admin_log 10 as admin_log %}
141 
142     Note that ``context_var_containing_user_obj`` can be a hard-coded integer
143     (user ID) or the name of a template context variable containing the user
144-    object whose ID you want.
145+    object whose ID you want. The ``context_var_containing_site_obj`` works the
146+    same way, except that when you omit a value, it uses the current site.
147     """
148     def __init__(self, tag_name):
149         self.tag_name = tag_name
150@@ -45,9 +66,14 @@
151             raise template.TemplateSyntaxError, "First argument in '%s' must be an integer" % self.tag_name
152         if tokens[2] != 'as':
153             raise template.TemplateSyntaxError, "Second argument in '%s' must be 'as'" % self.tag_name
154+        user = site = None
155         if len(tokens) > 4:
156-            if tokens[4] != 'for_user':
157-                raise template.TemplateSyntaxError, "Fourth argument in '%s' must be 'for_user'" % self.tag_name
158-        return AdminLogNode(limit=tokens[1], varname=tokens[3], user=(len(tokens) > 5 and tokens[5] or None))
159+            if tokens[4] not in ('for_user', 'for_site'):
160+                raise template.TemplateSyntaxError, "Fourth argument in '%s' must be 'for_user' or 'for_site'" % self.tag_name
161+            if tokens[4] == 'for_user':
162+                user = len(tokens) > 5 and tokens[5] or None
163+            else:
164+                site = len(tokens) > 5 and tokens[5] or str(settings.SITE_ID)
165+        return AdminLogNode(limit=tokens[1], varname=tokens[3], user=user, site=site)
166 
167 register.tag('get_admin_log', DoGetAdminLog('get_admin_log'))
168Index: django/contrib/admin/models.py
169===================================================================
170--- django/contrib/admin/models.py      (revision 3900)
171+++ django/contrib/admin/models.py      (working copy)
172@@ -1,6 +1,7 @@
173 from django.db import models
174 from django.contrib.contenttypes.models import ContentType
175 from django.contrib.auth.models import User
176+from django.contrib.sites.models import Site
177 from django.utils.translation import gettext_lazy as _
178 
179 ADDITION = 1
180@@ -8,13 +9,20 @@
181 DELETION = 3
182 
183 class LogEntryManager(models.Manager):
184-    def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
185-        e = self.model(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
186+    def log_action(self, user, model, obj, action, message=''):
187+        site_id = None
188+        site = Site.objects.get_for_object(obj)
189+        if site:
190+            site_id = site.id
191+        e = self.model(None, None, user.id, site_id,
192+                       ContentType.objects.get_for_model(model).id,
193+                       obj._get_pk_val(), str(obj)[:200], action, message)
194         e.save()
195 
196 class LogEntry(models.Model):
197     action_time = models.DateTimeField(_('action time'), auto_now=True)
198     user = models.ForeignKey(User)
199+    site = models.ForeignKey(Site, blank=True, null=True)
200     content_type = models.ForeignKey(ContentType, blank=True, null=True)
201     object_id = models.TextField(_('object id'), blank=True, null=True)
202     object_repr = models.CharField(_('object repr'), maxlength=200)
203Index: django/contrib/admin/views/main.py
204===================================================================
205--- django/contrib/admin/views/main.py  (revision 3900)
206+++ django/contrib/admin/views/main.py  (working copy)
207@@ -253,7 +253,7 @@
208         if not errors:
209             new_object = manipulator.save(new_data)
210             pk_value = new_object._get_pk_val()
211-            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), ADDITION)
212+            LogEntry.objects.log_action(request.user, model, new_object, ADDITION)
213             msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
214             # Here, we distinguish between different save types by checking for
215             # the presence of keys in request.POST.
216@@ -340,7 +340,7 @@
217             change_message = ' '.join(change_message)
218             if not change_message:
219                 change_message = _('No fields changed.')
220-            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message)
221+            LogEntry.objects.log_action(request.user, model, new_object, CHANGE, change_message)
222 
223             msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
224             if request.POST.has_key("_continue"):
225@@ -507,7 +507,7 @@
226             raise PermissionDenied
227         obj_display = str(obj)
228         obj.delete()
229-        LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, object_id, obj_display, DELETION)
230+        LogEntry.objects.log_action(request.user, model, obj, DELETION)
231         request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
232         return HttpResponseRedirect("../../")
233     extra_context = {