summaryrefslogtreecommitdiffstats
path: root/webapp/django/contrib/admin/views/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/contrib/admin/views/main.py')
-rw-r--r--webapp/django/contrib/admin/views/main.py233
1 files changed, 233 insertions, 0 deletions
diff --git a/webapp/django/contrib/admin/views/main.py b/webapp/django/contrib/admin/views/main.py
new file mode 100644
index 0000000000..50b015352d
--- /dev/null
+++ b/webapp/django/contrib/admin/views/main.py
@@ -0,0 +1,233 @@
+from django.contrib.admin.filterspecs import FilterSpec
+from django.contrib.admin.options import IncorrectLookupParameters
+from django.contrib.admin.util import quote
+from django.core.paginator import Paginator, InvalidPage
+from django.db import models
+from django.db.models.query import QuerySet
+from django.utils.encoding import force_unicode, smart_str
+from django.utils.translation import ugettext
+from django.utils.http import urlencode
+import operator
+
+try:
+ set
+except NameError:
+ from sets import Set as set # Python 2.3 fallback
+
+# The system will display a "Show all" link on the change list only if the
+# total result count is less than or equal to this setting.
+MAX_SHOW_ALL_ALLOWED = 200
+
+# Changelist settings
+ALL_VAR = 'all'
+ORDER_VAR = 'o'
+ORDER_TYPE_VAR = 'ot'
+PAGE_VAR = 'p'
+SEARCH_VAR = 'q'
+IS_POPUP_VAR = 'pop'
+ERROR_FLAG = 'e'
+
+# Text to display within change-list table cells if the value is blank.
+EMPTY_CHANGELIST_VALUE = '(None)'
+
+class ChangeList(object):
+ def __init__(self, request, model, list_display, list_display_links, list_filter, date_hierarchy, search_fields, list_select_related, list_per_page, model_admin):
+ self.model = model
+ self.opts = model._meta
+ self.lookup_opts = self.opts
+ self.root_query_set = model_admin.queryset(request)
+ self.list_display = list_display
+ self.list_display_links = list_display_links
+ self.list_filter = list_filter
+ self.date_hierarchy = date_hierarchy
+ self.search_fields = search_fields
+ self.list_select_related = list_select_related
+ self.list_per_page = list_per_page
+ self.model_admin = model_admin
+
+ # Get search parameters from the query string.
+ try:
+ self.page_num = int(request.GET.get(PAGE_VAR, 0))
+ except ValueError:
+ self.page_num = 0
+ self.show_all = ALL_VAR in request.GET
+ self.is_popup = IS_POPUP_VAR in request.GET
+ self.params = dict(request.GET.items())
+ if PAGE_VAR in self.params:
+ del self.params[PAGE_VAR]
+ if ERROR_FLAG in self.params:
+ del self.params[ERROR_FLAG]
+
+ self.order_field, self.order_type = self.get_ordering()
+ self.query = request.GET.get(SEARCH_VAR, '')
+ self.query_set = self.get_query_set()
+ self.get_results(request)
+ self.title = (self.is_popup and ugettext('Select %s') % force_unicode(self.opts.verbose_name) or ugettext('Select %s to change') % force_unicode(self.opts.verbose_name))
+ self.filter_specs, self.has_filters = self.get_filters(request)
+ self.pk_attname = self.lookup_opts.pk.attname
+
+ def get_filters(self, request):
+ filter_specs = []
+ if self.list_filter:
+ filter_fields = [self.lookup_opts.get_field(field_name) for field_name in self.list_filter]
+ for f in filter_fields:
+ spec = FilterSpec.create(f, request, self.params, self.model, self.model_admin)
+ if spec and spec.has_output():
+ filter_specs.append(spec)
+ return filter_specs, bool(filter_specs)
+
+ def get_query_string(self, new_params=None, remove=None):
+ if new_params is None: new_params = {}
+ if remove is None: remove = []
+ p = self.params.copy()
+ for r in remove:
+ for k in p.keys():
+ if k.startswith(r):
+ del p[k]
+ for k, v in new_params.items():
+ if v is None:
+ if k in p:
+ del p[k]
+ else:
+ p[k] = v
+ return '?%s' % urlencode(p)
+
+ def get_results(self, request):
+ paginator = Paginator(self.query_set, self.list_per_page)
+ # Get the number of objects, with admin filters applied.
+ try:
+ result_count = paginator.count
+ # Naked except! Because we don't have any other way of validating
+ # "params". They might be invalid if the keyword arguments are
+ # incorrect, or if the values are not in the correct type (which would
+ # result in a database error).
+ except:
+ raise IncorrectLookupParameters
+
+ # Get the total number of objects, with no admin filters applied.
+ # Perform a slight optimization: Check to see whether any filters were
+ # given. If not, use paginator.hits to calculate the number of objects,
+ # because we've already done paginator.hits and the value is cached.
+ if not self.query_set.query.where:
+ full_result_count = result_count
+ else:
+ full_result_count = self.root_query_set.count()
+
+ can_show_all = result_count <= MAX_SHOW_ALL_ALLOWED
+ multi_page = result_count > self.list_per_page
+
+ # Get the list of objects to display on this page.
+ if (self.show_all and can_show_all) or not multi_page:
+ result_list = list(self.query_set)
+ else:
+ try:
+ result_list = paginator.page(self.page_num+1).object_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
+
+ def get_ordering(self):
+ lookup_opts, params = self.lookup_opts, self.params
+ # For ordering, first check the "ordering" parameter in the admin
+ # options, then check the object's default ordering. If neither of
+ # those exist, order descending by ID by default. Finally, look for
+ # manually-specified ordering from the query string.
+ ordering = self.model_admin.ordering or lookup_opts.ordering or ['-' + lookup_opts.pk.name]
+
+ if ordering[0].startswith('-'):
+ order_field, order_type = ordering[0][1:], 'desc'
+ else:
+ order_field, order_type = ordering[0], 'asc'
+ if ORDER_VAR in params:
+ try:
+ field_name = self.list_display[int(params[ORDER_VAR])]
+ try:
+ f = lookup_opts.get_field(field_name)
+ except models.FieldDoesNotExist:
+ # See whether field_name is a name of a non-field
+ # that allows sorting.
+ try:
+ attr = getattr(self.model, field_name)
+ order_field = attr.admin_order_field
+ except AttributeError:
+ pass
+ else:
+ if not isinstance(f.rel, models.ManyToOneRel) or not f.null:
+ order_field = f.name
+ except (IndexError, ValueError):
+ pass # Invalid ordering specified. Just use the default.
+ if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'):
+ order_type = params[ORDER_TYPE_VAR]
+ return order_field, order_type
+
+ def get_query_set(self):
+ qs = self.root_query_set
+ lookup_params = self.params.copy() # a dictionary of the query string
+ for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR):
+ if i in lookup_params:
+ del lookup_params[i]
+ for key, value in lookup_params.items():
+ if not isinstance(key, str):
+ # 'key' will be used as a keyword argument later, so Python
+ # requires it to be a string.
+ del lookup_params[key]
+ lookup_params[smart_str(key)] = value
+
+ # Apply lookup parameters from the query string.
+ qs = qs.filter(**lookup_params)
+
+ # Use select_related() if one of the list_display options is a field
+ # with a relationship.
+ if self.list_select_related:
+ qs = qs.select_related()
+ else:
+ for field_name in self.list_display:
+ try:
+ f = self.lookup_opts.get_field(field_name)
+ except models.FieldDoesNotExist:
+ pass
+ else:
+ if isinstance(f.rel, models.ManyToOneRel):
+ qs = qs.select_related()
+ break
+
+ # Set ordering.
+ if self.order_field:
+ qs = qs.order_by('%s%s' % ((self.order_type == 'desc' and '-' or ''), self.order_field))
+
+ # Apply keyword searches.
+ def construct_search(field_name):
+ if field_name.startswith('^'):
+ return "%s__istartswith" % field_name[1:]
+ elif field_name.startswith('='):
+ return "%s__iexact" % field_name[1:]
+ elif field_name.startswith('@'):
+ return "%s__search" % field_name[1:]
+ else:
+ return "%s__icontains" % field_name
+
+ if self.search_fields and self.query:
+ for bit in self.query.split():
+ or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.search_fields]
+ other_qs = QuerySet(self.model)
+ other_qs.dup_select_related(qs)
+ other_qs = other_qs.filter(reduce(operator.or_, or_queries))
+ qs = qs & other_qs
+ for field_name in self.search_fields:
+ if '__' in field_name:
+ qs = qs.distinct()
+ break
+
+ if self.opts.one_to_one_field:
+ qs = qs.complex_filter(self.opts.one_to_one_field.rel.limit_choices_to)
+
+ return qs
+
+ def url_for_result(self, result):
+ return "%s/" % quote(getattr(result, self.pk_attname))