forked from django-haystack/django-haystack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadmin.py
More file actions
168 lines (146 loc) · 6.22 KB
/
admin.py
File metadata and controls
168 lines (146 loc) · 6.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# encoding: utf-8
from django.contrib.admin.options import ModelAdmin, csrf_protect_m
from django.contrib.admin.views.main import SEARCH_VAR, ChangeList
from django.core.exceptions import PermissionDenied
from django.core.paginator import InvalidPage, Paginator
from django.shortcuts import render
from django.utils.encoding import force_str
from django.utils.translation import ungettext
from haystack import connections
from haystack.constants import DEFAULT_ALIAS
from haystack.query import SearchQuerySet
from haystack.utils import get_model_ct_tuple
class SearchChangeList(ChangeList):
def __init__(self, **kwargs):
self.haystack_connection = kwargs.pop("haystack_connection", DEFAULT_ALIAS)
super(SearchChangeList, self).__init__(**kwargs)
def get_results(self, request):
if SEARCH_VAR not in request.GET:
return super(SearchChangeList, self).get_results(request)
# Note that pagination is 0-based, not 1-based.
sqs = (
SearchQuerySet(self.haystack_connection)
.models(self.model)
.auto_query(request.GET[SEARCH_VAR])
.load_all()
)
paginator = Paginator(sqs, self.list_per_page)
# Get the number of objects, with admin filters applied.
result_count = paginator.count
full_result_count = (
SearchQuerySet(self.haystack_connection).models(self.model).all().count()
)
can_show_all = result_count <= self.list_max_show_all
multi_page = result_count > self.list_per_page
# Get the list of objects to display on this page.
try:
result_list = paginator.page(self.page_num + 1).object_list
# Grab just the Django models, since that's what everything else is
# expecting.
result_list = [result.object for result in result_list]
except InvalidPage:
result_list = ()
self.result_count = result_count
self.full_result_count = full_result_count
self.result_list = result_list
self.can_show_all = can_show_all
self.multi_page = multi_page
self.paginator = paginator
class SearchModelAdminMixin(object):
# haystack connection to use for searching
haystack_connection = DEFAULT_ALIAS
@csrf_protect_m
def changelist_view(self, request, extra_context=None):
if not self.has_change_permission(request, None):
raise PermissionDenied
if SEARCH_VAR not in request.GET:
# Do the usual song and dance.
return super(SearchModelAdminMixin, self).changelist_view(
request, extra_context
)
# Do a search of just this model and populate a Changelist with the
# returned bits.
indexed_models = (
connections[self.haystack_connection]
.get_unified_index()
.get_indexed_models()
)
if self.model not in indexed_models:
# Oops. That model isn't being indexed. Return the usual
# behavior instead.
return super(SearchModelAdminMixin, self).changelist_view(
request, extra_context
)
# So. Much. Boilerplate.
# Why copy-paste a few lines when you can copy-paste TONS of lines?
list_display = list(self.list_display)
kwargs = {
"haystack_connection": self.haystack_connection,
"request": request,
"model": self.model,
"list_display": list_display,
"list_display_links": self.list_display_links,
"list_filter": self.list_filter,
"date_hierarchy": self.date_hierarchy,
"search_fields": self.search_fields,
"list_select_related": self.list_select_related,
"list_per_page": self.list_per_page,
"list_editable": self.list_editable,
"list_max_show_all": self.list_max_show_all,
"model_admin": self,
}
if hasattr(self, 'get_sortable_by'): # Django 2.1+
kwargs["sortable_by"] = self.get_sortable_by(request)
changelist = SearchChangeList(**kwargs)
changelist.formset = None
media = self.media
# Build the action form and populate it with available actions.
# Check actions to see if any are available on this changelist
actions = self.get_actions(request)
if actions:
action_form = self.action_form(auto_id=None)
action_form.fields["action"].choices = self.get_action_choices(request)
else:
action_form = None
selection_note = ungettext(
"0 of %(count)d selected",
"of %(count)d selected",
len(changelist.result_list),
)
selection_note_all = ungettext(
"%(total_count)s selected",
"All %(total_count)s selected",
changelist.result_count,
)
context = {
"module_name": force_str(self.model._meta.verbose_name_plural),
"selection_note": selection_note % {"count": len(changelist.result_list)},
"selection_note_all": selection_note_all
% {"total_count": changelist.result_count},
"title": changelist.title,
"is_popup": changelist.is_popup,
"cl": changelist,
"media": media,
"has_add_permission": self.has_add_permission(request),
"opts": changelist.opts,
"app_label": self.model._meta.app_label,
"action_form": action_form,
"actions_on_top": self.actions_on_top,
"actions_on_bottom": self.actions_on_bottom,
"actions_selection_counter": getattr(self, "actions_selection_counter", 0),
}
context.update(extra_context or {})
request.current_app = self.admin_site.name
app_name, model_name = get_model_ct_tuple(self.model)
return render(
request,
self.change_list_template
or [
"admin/%s/%s/change_list.html" % (app_name, model_name),
"admin/%s/change_list.html" % app_name,
"admin/change_list.html",
],
context,
)
class SearchModelAdmin(SearchModelAdminMixin, ModelAdmin):
pass