测试gitnore
This commit is contained in:
@@ -6,47 +6,31 @@ from django.views.generic.list import BaseListView
|
||||
|
||||
class AutocompleteJsonView(BaseListView):
|
||||
"""Handle AutocompleteWidget's AJAX requests for data."""
|
||||
|
||||
paginate_by = 20
|
||||
admin_site = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""
|
||||
Return a JsonResponse with search results as defined in
|
||||
serialize_result(), by default:
|
||||
Return a JsonResponse with search results of the form:
|
||||
{
|
||||
results: [{id: "123" text: "foo"}],
|
||||
pagination: {more: true}
|
||||
}
|
||||
"""
|
||||
(
|
||||
self.term,
|
||||
self.model_admin,
|
||||
self.source_field,
|
||||
to_field_name,
|
||||
) = self.process_request(request)
|
||||
self.term, self.model_admin, self.source_field, to_field_name = self.process_request(request)
|
||||
|
||||
if not self.has_perm(request):
|
||||
raise PermissionDenied
|
||||
|
||||
self.object_list = self.get_queryset()
|
||||
context = self.get_context_data()
|
||||
return JsonResponse(
|
||||
{
|
||||
"results": [
|
||||
self.serialize_result(obj, to_field_name)
|
||||
for obj in context["object_list"]
|
||||
],
|
||||
"pagination": {"more": context["page_obj"].has_next()},
|
||||
}
|
||||
)
|
||||
|
||||
def serialize_result(self, obj, to_field_name):
|
||||
"""
|
||||
Convert the provided model object to a dictionary that is added to the
|
||||
results list.
|
||||
"""
|
||||
return {"id": str(getattr(obj, to_field_name)), "text": str(obj)}
|
||||
return JsonResponse({
|
||||
'results': [
|
||||
{'id': str(getattr(obj, to_field_name)), 'text': str(obj)}
|
||||
for obj in context['object_list']
|
||||
],
|
||||
'pagination': {'more': context['page_obj'].has_next()},
|
||||
})
|
||||
|
||||
def get_paginator(self, *args, **kwargs):
|
||||
"""Use the ModelAdmin's paginator."""
|
||||
@@ -56,9 +40,7 @@ class AutocompleteJsonView(BaseListView):
|
||||
"""Return queryset based on ModelAdmin.get_search_results()."""
|
||||
qs = self.model_admin.get_queryset(self.request)
|
||||
qs = qs.complex_filter(self.source_field.get_limit_choices_to())
|
||||
qs, search_use_distinct = self.model_admin.get_search_results(
|
||||
self.request, qs, self.term
|
||||
)
|
||||
qs, search_use_distinct = self.model_admin.get_search_results(self.request, qs, self.term)
|
||||
if search_use_distinct:
|
||||
qs = qs.distinct()
|
||||
return qs
|
||||
@@ -74,11 +56,11 @@ class AutocompleteJsonView(BaseListView):
|
||||
Raise Http404 if the target model admin is not configured properly with
|
||||
search_fields.
|
||||
"""
|
||||
term = request.GET.get("term", "")
|
||||
term = request.GET.get('term', '')
|
||||
try:
|
||||
app_label = request.GET["app_label"]
|
||||
model_name = request.GET["model_name"]
|
||||
field_name = request.GET["field_name"]
|
||||
app_label = request.GET['app_label']
|
||||
model_name = request.GET['model_name']
|
||||
field_name = request.GET['field_name']
|
||||
except KeyError as e:
|
||||
raise PermissionDenied from e
|
||||
|
||||
@@ -104,13 +86,11 @@ class AutocompleteJsonView(BaseListView):
|
||||
# Validate suitability of objects.
|
||||
if not model_admin.get_search_fields(request):
|
||||
raise Http404(
|
||||
"%s must have search_fields for the autocomplete_view."
|
||||
% type(model_admin).__qualname__
|
||||
'%s must have search_fields for the autocomplete_view.' %
|
||||
type(model_admin).__qualname__
|
||||
)
|
||||
|
||||
to_field_name = getattr(
|
||||
source_field.remote_field, "field_name", remote_model._meta.pk.attname
|
||||
)
|
||||
to_field_name = getattr(source_field.remote_field, 'field_name', remote_model._meta.pk.attname)
|
||||
to_field_name = remote_model._meta.get_field(to_field_name).attname
|
||||
if not model_admin.to_field_allowed(request, to_field_name):
|
||||
raise PermissionDenied
|
||||
|
||||
@@ -2,9 +2,8 @@ from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
|
||||
|
||||
def staff_member_required(
|
||||
view_func=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url="admin:login"
|
||||
):
|
||||
def staff_member_required(view_func=None, redirect_field_name=REDIRECT_FIELD_NAME,
|
||||
login_url='admin:login'):
|
||||
"""
|
||||
Decorator for views that checks that the user is logged in and is a staff
|
||||
member, redirecting to the login page if necessary.
|
||||
@@ -12,7 +11,7 @@ def staff_member_required(
|
||||
actual_decorator = user_passes_test(
|
||||
lambda u: u.is_active and u.is_staff,
|
||||
login_url=login_url,
|
||||
redirect_field_name=redirect_field_name,
|
||||
redirect_field_name=redirect_field_name
|
||||
)
|
||||
if view_func:
|
||||
return actual_decorator(view_func)
|
||||
|
||||
@@ -5,24 +5,16 @@ from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.admin import FieldListFilter
|
||||
from django.contrib.admin.exceptions import (
|
||||
DisallowedModelAdminLookup,
|
||||
DisallowedModelAdminToField,
|
||||
DisallowedModelAdminLookup, DisallowedModelAdminToField,
|
||||
)
|
||||
from django.contrib.admin.options import (
|
||||
IS_POPUP_VAR,
|
||||
TO_FIELD_VAR,
|
||||
IncorrectLookupParameters,
|
||||
IS_POPUP_VAR, TO_FIELD_VAR, IncorrectLookupParameters,
|
||||
)
|
||||
from django.contrib.admin.utils import (
|
||||
get_fields_from_path,
|
||||
lookup_spawns_duplicates,
|
||||
prepare_lookup_value,
|
||||
quote,
|
||||
get_fields_from_path, lookup_needs_distinct, prepare_lookup_value, quote,
|
||||
)
|
||||
from django.core.exceptions import (
|
||||
FieldDoesNotExist,
|
||||
ImproperlyConfigured,
|
||||
SuspiciousOperation,
|
||||
FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation,
|
||||
)
|
||||
from django.core.paginator import InvalidPage
|
||||
from django.db.models import Exists, F, Field, ManyToOneRel, OrderBy, OuterRef
|
||||
@@ -33,13 +25,15 @@ from django.utils.timezone import make_aware
|
||||
from django.utils.translation import gettext
|
||||
|
||||
# Changelist settings
|
||||
ALL_VAR = "all"
|
||||
ORDER_VAR = "o"
|
||||
PAGE_VAR = "p"
|
||||
SEARCH_VAR = "q"
|
||||
ERROR_FLAG = "e"
|
||||
ALL_VAR = 'all'
|
||||
ORDER_VAR = 'o'
|
||||
ORDER_TYPE_VAR = 'ot'
|
||||
PAGE_VAR = 'p'
|
||||
SEARCH_VAR = 'q'
|
||||
ERROR_FLAG = 'e'
|
||||
|
||||
IGNORED_PARAMS = (ALL_VAR, ORDER_VAR, SEARCH_VAR, IS_POPUP_VAR, TO_FIELD_VAR)
|
||||
IGNORED_PARAMS = (
|
||||
ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR, TO_FIELD_VAR)
|
||||
|
||||
|
||||
class ChangeListSearchForm(forms.Form):
|
||||
@@ -54,23 +48,9 @@ class ChangeListSearchForm(forms.Form):
|
||||
class ChangeList:
|
||||
search_form_class = ChangeListSearchForm
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request,
|
||||
model,
|
||||
list_display,
|
||||
list_display_links,
|
||||
list_filter,
|
||||
date_hierarchy,
|
||||
search_fields,
|
||||
list_select_related,
|
||||
list_per_page,
|
||||
list_max_show_all,
|
||||
list_editable,
|
||||
model_admin,
|
||||
sortable_by,
|
||||
search_help_text,
|
||||
):
|
||||
def __init__(self, request, model, list_display, list_display_links,
|
||||
list_filter, date_hierarchy, search_fields, list_select_related,
|
||||
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by):
|
||||
self.model = model
|
||||
self.opts = model._meta
|
||||
self.lookup_opts = self.opts
|
||||
@@ -89,14 +69,13 @@ class ChangeList:
|
||||
self.model_admin = model_admin
|
||||
self.preserved_filters = model_admin.get_preserved_filters(request)
|
||||
self.sortable_by = sortable_by
|
||||
self.search_help_text = search_help_text
|
||||
|
||||
# Get search parameters from the query string.
|
||||
_search_form = self.search_form_class(request.GET)
|
||||
if not _search_form.is_valid():
|
||||
for error in _search_form.errors.values():
|
||||
messages.error(request, ", ".join(error))
|
||||
self.query = _search_form.cleaned_data.get(SEARCH_VAR) or ""
|
||||
messages.error(request, ', '.join(error))
|
||||
self.query = _search_form.cleaned_data.get(SEARCH_VAR) or ''
|
||||
try:
|
||||
self.page_num = int(request.GET.get(PAGE_VAR, 1))
|
||||
except ValueError:
|
||||
@@ -105,9 +84,7 @@ class ChangeList:
|
||||
self.is_popup = IS_POPUP_VAR in request.GET
|
||||
to_field = request.GET.get(TO_FIELD_VAR)
|
||||
if to_field and not model_admin.to_field_allowed(request, to_field):
|
||||
raise DisallowedModelAdminToField(
|
||||
"The field %s cannot be referenced." % to_field
|
||||
)
|
||||
raise DisallowedModelAdminToField("The field %s cannot be referenced." % to_field)
|
||||
self.to_field = to_field
|
||||
self.params = dict(request.GET.items())
|
||||
if PAGE_VAR in self.params:
|
||||
@@ -122,21 +99,14 @@ class ChangeList:
|
||||
self.queryset = self.get_queryset(request)
|
||||
self.get_results(request)
|
||||
if self.is_popup:
|
||||
title = gettext("Select %s")
|
||||
title = gettext('Select %s')
|
||||
elif self.model_admin.has_change_permission(request):
|
||||
title = gettext("Select %s to change")
|
||||
title = gettext('Select %s to change')
|
||||
else:
|
||||
title = gettext("Select %s to view")
|
||||
title = gettext('Select %s to view')
|
||||
self.title = title % self.opts.verbose_name
|
||||
self.pk_attname = self.lookup_opts.pk.attname
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: model=%s model_admin=%s>" % (
|
||||
self.__class__.__qualname__,
|
||||
self.model.__qualname__,
|
||||
self.model_admin.__class__.__qualname__,
|
||||
)
|
||||
|
||||
def get_filters_params(self, params=None):
|
||||
"""
|
||||
Return all params except IGNORED_PARAMS.
|
||||
@@ -180,21 +150,14 @@ class ChangeList:
|
||||
field = get_fields_from_path(self.model, field_path)[-1]
|
||||
|
||||
spec = field_list_filter_class(
|
||||
field,
|
||||
request,
|
||||
lookup_params,
|
||||
self.model,
|
||||
self.model_admin,
|
||||
field_path=field_path,
|
||||
field, request, lookup_params,
|
||||
self.model, self.model_admin, field_path=field_path,
|
||||
)
|
||||
# field_list_filter_class removes any lookup_params it
|
||||
# processes. If that happened, check if duplicates should be
|
||||
# removed.
|
||||
# processes. If that happened, check if distinct() is needed to
|
||||
# remove duplicate results.
|
||||
if lookup_params_count > len(lookup_params):
|
||||
may_have_duplicates |= lookup_spawns_duplicates(
|
||||
self.lookup_opts,
|
||||
field_path,
|
||||
)
|
||||
may_have_duplicates |= lookup_needs_distinct(self.lookup_opts, field_path)
|
||||
if spec and spec.has_output():
|
||||
filter_specs.append(spec)
|
||||
if lookup_params_count > len(lookup_params):
|
||||
@@ -203,10 +166,10 @@ class ChangeList:
|
||||
if self.date_hierarchy:
|
||||
# Create bounded lookup parameters so that the query is more
|
||||
# efficient.
|
||||
year = lookup_params.pop("%s__year" % self.date_hierarchy, None)
|
||||
year = lookup_params.pop('%s__year' % self.date_hierarchy, None)
|
||||
if year is not None:
|
||||
month = lookup_params.pop("%s__month" % self.date_hierarchy, None)
|
||||
day = lookup_params.pop("%s__day" % self.date_hierarchy, None)
|
||||
month = lookup_params.pop('%s__month' % self.date_hierarchy, None)
|
||||
day = lookup_params.pop('%s__day' % self.date_hierarchy, None)
|
||||
try:
|
||||
from_date = datetime(
|
||||
int(year),
|
||||
@@ -226,28 +189,23 @@ class ChangeList:
|
||||
if settings.USE_TZ:
|
||||
from_date = make_aware(from_date)
|
||||
to_date = make_aware(to_date)
|
||||
lookup_params.update(
|
||||
{
|
||||
"%s__gte" % self.date_hierarchy: from_date,
|
||||
"%s__lt" % self.date_hierarchy: to_date,
|
||||
}
|
||||
)
|
||||
lookup_params.update({
|
||||
'%s__gte' % self.date_hierarchy: from_date,
|
||||
'%s__lt' % self.date_hierarchy: to_date,
|
||||
})
|
||||
|
||||
# At this point, all the parameters used by the various ListFilters
|
||||
# have been removed from lookup_params, which now only contains other
|
||||
# parameters passed via the query string. We now loop through the
|
||||
# remaining parameters both to ensure that all the parameters are valid
|
||||
# fields and to determine if at least one of them spawns duplicates. If
|
||||
# fields and to determine if at least one of them needs distinct(). If
|
||||
# the lookup parameters aren't real fields, then bail out.
|
||||
try:
|
||||
for key, value in lookup_params.items():
|
||||
lookup_params[key] = prepare_lookup_value(key, value)
|
||||
may_have_duplicates |= lookup_spawns_duplicates(self.lookup_opts, key)
|
||||
may_have_duplicates |= lookup_needs_distinct(self.lookup_opts, key)
|
||||
return (
|
||||
filter_specs,
|
||||
bool(filter_specs),
|
||||
lookup_params,
|
||||
may_have_duplicates,
|
||||
filter_specs, bool(filter_specs), lookup_params, may_have_duplicates,
|
||||
has_active_filters,
|
||||
)
|
||||
except FieldDoesNotExist as e:
|
||||
@@ -269,12 +227,10 @@ class ChangeList:
|
||||
del p[k]
|
||||
else:
|
||||
p[k] = v
|
||||
return "?%s" % urlencode(sorted(p.items()))
|
||||
return '?%s' % urlencode(sorted(p.items()))
|
||||
|
||||
def get_results(self, request):
|
||||
paginator = self.model_admin.get_paginator(
|
||||
request, self.queryset, self.list_per_page
|
||||
)
|
||||
paginator = self.model_admin.get_paginator(request, self.queryset, self.list_per_page)
|
||||
# Get the number of objects, with admin filters applied.
|
||||
result_count = paginator.count
|
||||
|
||||
@@ -299,9 +255,7 @@ class ChangeList:
|
||||
self.show_full_result_count = self.model_admin.show_full_result_count
|
||||
# Admin actions are shown if there is at least one entry
|
||||
# or if entries are not counted because show_full_result_count is disabled
|
||||
self.show_admin_actions = not self.show_full_result_count or bool(
|
||||
full_result_count
|
||||
)
|
||||
self.show_admin_actions = not self.show_full_result_count or bool(full_result_count)
|
||||
self.full_result_count = full_result_count
|
||||
self.result_list = result_list
|
||||
self.can_show_all = can_show_all
|
||||
@@ -336,9 +290,9 @@ class ChangeList:
|
||||
attr = getattr(self.model_admin, field_name)
|
||||
else:
|
||||
attr = getattr(self.model, field_name)
|
||||
if isinstance(attr, property) and hasattr(attr, "fget"):
|
||||
if isinstance(attr, property) and hasattr(attr, 'fget'):
|
||||
attr = attr.fget
|
||||
return getattr(attr, "admin_order_field", None)
|
||||
return getattr(attr, 'admin_order_field', None)
|
||||
|
||||
def get_ordering(self, request, queryset):
|
||||
"""
|
||||
@@ -350,32 +304,28 @@ class ChangeList:
|
||||
constructed ordering.
|
||||
"""
|
||||
params = self.params
|
||||
ordering = list(
|
||||
self.model_admin.get_ordering(request) or self._get_default_ordering()
|
||||
)
|
||||
ordering = list(self.model_admin.get_ordering(request) or self._get_default_ordering())
|
||||
if ORDER_VAR in params:
|
||||
# Clear ordering and used params
|
||||
ordering = []
|
||||
order_params = params[ORDER_VAR].split(".")
|
||||
order_params = params[ORDER_VAR].split('.')
|
||||
for p in order_params:
|
||||
try:
|
||||
none, pfx, idx = p.rpartition("-")
|
||||
none, pfx, idx = p.rpartition('-')
|
||||
field_name = self.list_display[int(idx)]
|
||||
order_field = self.get_ordering_field(field_name)
|
||||
if not order_field:
|
||||
continue # No 'admin_order_field', skip it
|
||||
if isinstance(order_field, OrderBy):
|
||||
if pfx == "-":
|
||||
if pfx == '-':
|
||||
order_field = order_field.copy()
|
||||
order_field.reverse_ordering()
|
||||
ordering.append(order_field)
|
||||
elif hasattr(order_field, "resolve_expression"):
|
||||
elif hasattr(order_field, 'resolve_expression'):
|
||||
# order_field is an expression.
|
||||
ordering.append(
|
||||
order_field.desc() if pfx == "-" else order_field.asc()
|
||||
)
|
||||
ordering.append(order_field.desc() if pfx == '-' else order_field.asc())
|
||||
# reverse order if order_field has already "-" as prefix
|
||||
elif order_field.startswith("-") and pfx == "-":
|
||||
elif order_field.startswith('-') and pfx == '-':
|
||||
ordering.append(order_field[1:])
|
||||
else:
|
||||
ordering.append(pfx + order_field)
|
||||
@@ -396,16 +346,15 @@ class ChangeList:
|
||||
"""
|
||||
ordering = list(ordering)
|
||||
ordering_fields = set()
|
||||
total_ordering_fields = {"pk"} | {
|
||||
field.attname
|
||||
for field in self.lookup_opts.fields
|
||||
total_ordering_fields = {'pk'} | {
|
||||
field.attname for field in self.lookup_opts.fields
|
||||
if field.unique and not field.null
|
||||
}
|
||||
for part in ordering:
|
||||
# Search for single field providing a total ordering.
|
||||
field_name = None
|
||||
if isinstance(part, str):
|
||||
field_name = part.lstrip("-")
|
||||
field_name = part.lstrip('-')
|
||||
elif isinstance(part, F):
|
||||
field_name = part.name
|
||||
elif isinstance(part, OrderBy) and isinstance(part.expression, F):
|
||||
@@ -437,9 +386,7 @@ class ChangeList:
|
||||
)
|
||||
for field_names in constraint_field_names:
|
||||
# Normalize attname references by using get_field().
|
||||
fields = [
|
||||
self.lookup_opts.get_field(field_name) for field_name in field_names
|
||||
]
|
||||
fields = [self.lookup_opts.get_field(field_name) for field_name in field_names]
|
||||
# Composite unique constraints containing a nullable column
|
||||
# cannot ensure total ordering.
|
||||
if any(field.null for field in fields):
|
||||
@@ -449,7 +396,7 @@ class ChangeList:
|
||||
else:
|
||||
# If no set of unique fields is present in the ordering, rely
|
||||
# on the primary key to provide total ordering.
|
||||
ordering.append("-pk")
|
||||
ordering.append('-pk')
|
||||
return ordering
|
||||
|
||||
def get_ordering_field_columns(self):
|
||||
@@ -469,27 +416,27 @@ class ChangeList:
|
||||
if not isinstance(field, OrderBy):
|
||||
field = field.asc()
|
||||
if isinstance(field.expression, F):
|
||||
order_type = "desc" if field.descending else "asc"
|
||||
order_type = 'desc' if field.descending else 'asc'
|
||||
field = field.expression.name
|
||||
else:
|
||||
continue
|
||||
elif field.startswith("-"):
|
||||
elif field.startswith('-'):
|
||||
field = field[1:]
|
||||
order_type = "desc"
|
||||
order_type = 'desc'
|
||||
else:
|
||||
order_type = "asc"
|
||||
order_type = 'asc'
|
||||
for index, attr in enumerate(self.list_display):
|
||||
if self.get_ordering_field(attr) == field:
|
||||
ordering_fields[index] = order_type
|
||||
break
|
||||
else:
|
||||
for p in self.params[ORDER_VAR].split("."):
|
||||
none, pfx, idx = p.rpartition("-")
|
||||
for p in self.params[ORDER_VAR].split('.'):
|
||||
none, pfx, idx = p.rpartition('-')
|
||||
try:
|
||||
idx = int(idx)
|
||||
except ValueError:
|
||||
continue # skip it
|
||||
ordering_fields[idx] = "desc" if pfx == "-" else "asc"
|
||||
ordering_fields[idx] = 'desc' if pfx == '-' else 'asc'
|
||||
return ordering_fields
|
||||
|
||||
def get_queryset(self, request):
|
||||
@@ -527,9 +474,7 @@ class ChangeList:
|
||||
|
||||
# Apply search results
|
||||
qs, search_may_have_duplicates = self.model_admin.get_search_results(
|
||||
request,
|
||||
qs,
|
||||
self.query,
|
||||
request, qs, self.query,
|
||||
)
|
||||
|
||||
# Set query string for clearing all filters.
|
||||
@@ -539,7 +484,7 @@ class ChangeList:
|
||||
)
|
||||
# Remove duplicates from results, if necessary
|
||||
if filters_may_have_duplicates | search_may_have_duplicates:
|
||||
qs = qs.filter(pk=OuterRef("pk"))
|
||||
qs = qs.filter(pk=OuterRef('pk'))
|
||||
qs = self.root_queryset.filter(Exists(qs))
|
||||
|
||||
# Set ordering.
|
||||
@@ -578,8 +523,7 @@ class ChangeList:
|
||||
|
||||
def url_for_result(self, result):
|
||||
pk = getattr(result, self.pk_attname)
|
||||
return reverse(
|
||||
"admin:%s_%s_change" % (self.opts.app_label, self.opts.model_name),
|
||||
args=(quote(pk),),
|
||||
current_app=self.model_admin.admin_site.name,
|
||||
)
|
||||
return reverse('admin:%s_%s_change' % (self.opts.app_label,
|
||||
self.opts.model_name),
|
||||
args=(quote(pk),),
|
||||
current_app=self.model_admin.admin_site.name)
|
||||
|
||||
Reference in New Issue
Block a user