blob: b677b54ff94cbc39ea1975834c68a18e17987178 [file] [log] [blame]
Scott Baker25467ff2016-08-04 09:50:22 -07001from django.contrib import admin
2
3from django import forms
4from services.hpc.models import HpcService
5from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, SliderWidget, ServicePrivilegeInline
6from core.middleware import get_request
7
8from functools import update_wrapper
9from django.contrib.admin.views.main import ChangeList
10from django.core.urlresolvers import reverse, NoReverseMatch
11from django.contrib.admin.utils import quote
12
13import threading
14_thread_locals = threading.local()
15
16class FilteredChangeList(ChangeList):
17 """ A special ChangeList with a doctored url_for_result function that
18 points to the filteredchange view instead of the default change
19 view.
20 """
21
22 def __init__(self, request, *args, **kwargs):
23 self.service = getattr(request, "hpcService", None)
24 self.embedded = getattr(request, "embedded", False)
25 super(FilteredChangeList, self).__init__(request, *args, **kwargs)
26
27 def url_for_result(self, result):
28 if (self.service is None):
29 return super(FilteredChangeList, self).url_for_result(result)
30
31 pk = getattr(result, self.pk_attname)
32 if self.embedded:
33 return reverse('admin:%s_%s_embeddedfilteredchange' % (self.opts.app_label,
34 self.opts.model_name),
35 args=(quote(self.service.id), quote(pk),),
36 current_app=self.model_admin.admin_site.name)
37
38 else:
39 return reverse('admin:%s_%s_filteredchange' % (self.opts.app_label,
40 self.opts.model_name),
41 args=(quote(self.service.id), quote(pk),),
42 current_app=self.model_admin.admin_site.name)
43
44class FilteredAdmin(ReadOnlyAwareAdmin):
45 """
46 One approach to filtering the HPC Admin views by HPCService. Encode
47 the HPCService into the URL for the changelist view. Then we could do our
48 custom filtering in self.filtered_changelist_view.
49
50 To make this work, a few changes needed to be made to the change and
51 change_list templates.
52
53 1) "custom_changelist_breadcrumb_url" is used to replace the breadcrumb
54 in change and add views with one that will point back to the filtered
55 list.
56
57 2) "custom_add_url" is used to replace the Add button's URL with one
58 that points to the filtered add view.
59
60 TODO: Save & Add Another,
61 the add link when the changelist is empty
62 """
63
64 @property
65 def change_list_template(self):
66 return _thread_locals.change_list_template
67
68 @property
69 def change_form_template(self):
70 return _thread_locals.change_form_template
71
72 def get_urls(self):
73 from django.conf.urls import patterns, url
74
75 def wrap(view):
76 def wrapper(*args, **kwargs):
77 return self.admin_site.admin_view(view)(*args, **kwargs)
78 return update_wrapper(wrapper, view)
79
80 urls = super(FilteredAdmin, self).get_urls()
81 info = self.model._meta.app_label, self.model._meta.model_name
82 my_urls = [
83 url(r'^(.+)/filteredlist/$', wrap(self.filtered_changelist_view), name="%s_%s_filteredchangelist" % info),
84 url(r'^(.+)/embeddedfilteredlist/$', wrap(self.embedded_filtered_changelist_view), name="%s_%s_embeddedfilteredchangelist" % info),
85 url(r'^(.+)/(.+)/filteredchange$', wrap(self.filtered_change_view), name='%s_%s_filteredchange' % info),
86 url(r'^(.+)/(.+)/embeddedfilteredchange$', wrap(self.embedded_filtered_change_view), name='%s_%s_embeddedfilteredchange' % info),
87 url(r'^(.+)/filteredadd/$', wrap(self.filtered_add_view), name='%s_%s_filteredadd' % info),
88 url(r'^(.+)/embeddedfilteredadd/$', wrap(self.embedded_filtered_add_view), name='%s_%s_embeddedfilteredadd' % info),
89 ]
90 return my_urls + urls
91
92 def add_extra_context(self, request, extra_context):
93 super(FilteredAdmin, self).add_extra_context(request, extra_context)
94
95 if getattr(request,"hpcService",None) is not None:
96 extra_context["custom_changelist_breadcrumb_url"] = "/admin/hpc/%s/%s/filteredlist/" % (self.model._meta.model_name, str(request.hpcService.id))
97 if getattr(request,"embedded",False):
98 extra_context["custom_add_url"] = "/admin/hpc/%s/%s/embeddedfilteredadd/" % (self.model._meta.model_name, str(request.hpcService.id))
99 else:
100 extra_context["custom_add_url"] = "/admin/hpc/%s/%s/filteredadd/" % (self.model._meta.model_name, str(request.hpcService.id))
101 if len(request.resolver_match.args)>1:
102 # this is only useful on change views, not changelist views
103 extra_context["custom_delete_url"] = "/admin/hpc/%s/%s/delete/" % (self.model._meta.model_name, request.resolver_match.args[1])
104
105 extra_context["show_save"] = False
106 extra_context["show_save_and_add_another"] = False
107
108 def changelist_view(self, *args, **kwargs):
109 if "template" in kwargs:
110 _thread_locals.change_list_template = kwargs["template"]
111 del kwargs["template"]
112 else:
113 _thread_locals.change_list_template = "admin/change_list_bc.html"
114 return super(FilteredAdmin, self).changelist_view(*args, **kwargs)
115
116 def filtered_changelist_view(self, request, hpcServiceId, extra_context=None):
117 request.hpcService = HpcService.objects.get(id=hpcServiceId)
118 return self.changelist_view(request, extra_context=extra_context)
119
120 def embedded_filtered_changelist_view(self, request, hpcServiceId, extra_context=None):
121 request.hpcService = HpcService.objects.get(id=hpcServiceId)
122 request.embedded = True
123 return self.changelist_view(request, template="admin/change_list_embedded.html", extra_context=extra_context)
124
125 def change_view(self, *args, **kwargs):
126 if "template" in kwargs:
127 _thread_locals.change_form_template = kwargs["template"]
128 del kwargs["template"]
129 else:
130 _thread_locals.change_form_template = "admin/change_form_bc.html"
131 return super(FilteredAdmin, self).change_view(*args, **kwargs)
132
133 def filtered_change_view(self, request, hpcServiceId, object_id, extra_context=None):
134 request.hpcService = HpcService.objects.get(id=hpcServiceId)
135 return self.change_view(request, object_id, extra_context=extra_context)
136
137 def embedded_filtered_change_view(self, request, hpcServiceId, object_id, extra_context=None):
138 request.hpcService = HpcService.objects.get(id=hpcServiceId)
139 request.embedded = True
140 return self.change_view(request, object_id, template="admin/change_form_embedded.html", extra_context=extra_context)
141
142 def add_view(self, *args, **kwargs):
143 if "template" in kwargs:
144 _thread_locals.change_form_template = kwargs["template"]
145 del kwargs["template"]
146 else:
147 _thread_locals.change_form_template = "admin/change_form_bc.html"
148 return super(FilteredAdmin, self).add_view(*args, **kwargs)
149
150 def filtered_add_view(self, request, hpcServiceId, extra_context=None):
151 request.hpcService = HpcService.objects.get(id=hpcServiceId)
152 return self.add_view(request, extra_context=extra_context)
153
154 def embedded_filtered_add_view(self, request, hpcServiceId, extra_context=None):
155 request.hpcService = HpcService.objects.get(id=hpcServiceId)
156 request.embedded = True
157 return self.add_view(request, template="admin/change_form_embedded.html", extra_context=extra_context)
158
159 def get_queryset(self, request):
160 # request.hpcService will be set in filtered_changelist_view so we can
161 # use it to filter what will be displayed in the list.
162 qs = self.model.objects.all()
163 if (getattr(request,"hpcService",None) is not None) and (hasattr(self.model, "filter_by_hpcService")):
164 qs = self.model.filter_by_hpcService(qs, request.hpcService)
165 return qs
166
167 def get_changelist(self, request, **kwargs):
168 # We implement a custom ChangeList, so the URLs point to the
169 # filtered_change_view rather than the default change_view.
170 return FilteredChangeList
171
172class FilteredInline(XOSTabularInline):
173 def get_change_url(self, id):
174 request = get_request()
175 embedded = getattr(request, "embedded", False)
176 service_id = request.resolver_match.args[0]
177
178 if embedded:
179 reverse_path = "admin:%s_embeddedfilteredchange" % (self.selflink_model._meta.db_table)
180 args = (service_id, id)
181 else:
182 reverse_path = "admin:%s_filteredchange" % (self.selflink_model._meta.db_table)
183 args = (service_id, id)
184
185 try:
186 url = reverse(reverse_path, args=args, current_app=self.selflink_model._meta.app_label)
187 except NoReverseMatch:
188 return None
189
190 return url
191