magic-removal: Got admin changelist working with descriptor fields

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2213 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2006-02-01 04:58:42 +00:00
parent b01b9e3a87
commit 2cdd5b1b37
2 changed files with 111 additions and 116 deletions

View File

@ -127,7 +127,7 @@ def items_for_result(cl, result):
if isinstance(f.rel, models.ManyToOne):
if field_val is not None:
result_repr = getattr(result, 'get_%s' % f.name)()
result_repr = getattr(result, f.name)
else:
result_repr = EMPTY_CHANGELIST_VALUE
# Dates and times are special: They're formatted in a certain way.
@ -186,25 +186,17 @@ def result_list(cl):
result_list = register.inclusion_tag("admin/change_list_results")(result_list)
def date_hierarchy(cl):
lookup_opts, params, lookup_params, manager = \
cl.lookup_opts, cl.params, cl.lookup_params, cl.manager
if lookup_opts.admin.date_hierarchy:
field_name = lookup_opts.admin.date_hierarchy
if cl.lookup_opts.admin.date_hierarchy:
field_name = cl.lookup_opts.admin.date_hierarchy
year_field = '%s__year' % field_name
month_field = '%s__month' % field_name
day_field = '%s__day' % field_name
field_generic = '%s__' % field_name
year_lookup = params.get(year_field)
month_lookup = params.get(month_field)
day_lookup = params.get(day_field)
year_lookup = cl.params.get(year_field)
month_lookup = cl.params.get(month_field)
day_lookup = cl.params.get(day_field)
def link(d):
return cl.get_query_string(d, [field_generic])
def get_dates(unit, params):
return getattr(manager, 'get_%s_list' % field_name)(unit, **params)
link = lambda d: cl.get_query_string(d, [field_generic])
if year_lookup and month_lookup and day_lookup:
month_name = MONTHS[int(month_lookup)]
@ -217,9 +209,7 @@ def date_hierarchy(cl):
'choices': [{'title': "%s %s" % (month_name, day_lookup)}]
}
elif year_lookup and month_lookup:
date_lookup_params = lookup_params.copy()
date_lookup_params.update({year_field: year_lookup, month_field: month_lookup})
days = get_dates('day', date_lookup_params)
days = cl.query_set.filter(**{year_field: year_lookup, month_field: month_lookup}).dates(field_name, 'day')
return {
'show': True,
'back': {
@ -232,9 +222,7 @@ def date_hierarchy(cl):
} for day in days]
}
elif year_lookup:
date_lookup_params = lookup_params.copy()
date_lookup_params.update({year_field: year_lookup})
months = get_dates('month', date_lookup_params)
months = cl.query_set.filter(**{year_field: year_lookup}).dates(field_name, 'month')
return {
'show' : True,
'back': {
@ -242,18 +230,18 @@ def date_hierarchy(cl):
'title': _('All dates')
},
'choices': [{
'link': link( {year_field: year_lookup, month_field: month.month}),
'title': "%s %s" % (month.strftime('%B') , month.year)
'link': link({year_field: year_lookup, month_field: month.month}),
'title': "%s %s" % (month.strftime('%B'), month.year)
} for month in months]
}
else:
years = get_dates('year', lookup_params)
years = cl.query_set.dates(field_name, 'year')
return {
'show': True,
'choices': [{
'link': link({year_field: year.year}),
'title': year.year
} for year in years ]
} for year in years]
}
date_hierarchy = register.inclusion_tag('admin/date_hierarchy')(date_hierarchy)

View File

@ -6,7 +6,7 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, Per
from django.core.paginator import ObjectPaginator, InvalidPage
from django.shortcuts import get_object_or_404, render_to_response
from django.db import models
from django.db.models.query import handle_legacy_orderlist
from django.db.models.query import handle_legacy_orderlist, QuerySet
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.template import loader
from django.utils import dateformat
@ -467,8 +467,8 @@ def history(request, app_label, model_name, object_id):
model = models.get_model(app_label, model_name)
if model is None:
raise Http404, "App %r, model %r, not found" % (app_label, model_name)
action_list = LogEntry.objects.get_list(object_id__exact=object_id, content_type__id__exact=model._meta.get_content_type_id(),
order_by=("action_time",), select_related=True)
action_list = LogEntry.objects.filter(object_id=object_id,
content_type__id__exact=model._meta.get_content_type_id()).select_related().order_by('action_time')
# If no history was found, see whether this object even exists.
obj = get_object_or_404(model, pk=object_id)
return render_to_response('admin/object_history', {
@ -482,30 +482,39 @@ history = staff_member_required(history)
class ChangeList(object):
def __init__(self, request, model):
self.model = model
self.opts = self.model._meta
self.opts = model._meta
self.lookup_opts = self.opts
self.manager = self.model._default_manager
self.get_search_parameters(request)
self.get_ordering()
self.manager = model._default_manager
# 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 = request.GET.has_key(ALL_VAR)
self.is_popup = request.GET.has_key(IS_POPUP_VAR)
self.params = dict(request.GET.items())
if self.params.has_key(PAGE_VAR):
del self.params[PAGE_VAR]
self.order_field, self.order_type = self.get_ordering()
self.query = request.GET.get(SEARCH_VAR, '')
self.get_lookup_params()
self.query_set = self.get_query_set()
self.get_results(request)
self.title = (self.is_popup
and _('Select %s') % self.opts.verbose_name
or _('Select %s to change') % self.opts.verbose_name)
self.get_filters(request)
self.title = (self.is_popup and _('Select %s') % self.opts.verbose_name or _('Select %s to change') % 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):
self.filter_specs = []
filter_specs = []
if self.lookup_opts.admin.list_filter and not self.opts.one_to_one_field:
filter_fields = [self.lookup_opts.get_field(field_name) \
for field_name in self.lookup_opts.admin.list_filter]
for f in filter_fields:
spec = FilterSpec.create(f, request, self.params)
if spec and spec.has_output():
self.filter_specs.append(spec)
self.has_filters = bool(self.filter_specs)
filter_specs.append(spec)
return filter_specs, bool(filter_specs)
def get_query_string(self, new_params={}, remove=[]):
p = self.params.copy()
@ -520,57 +529,46 @@ class ChangeList(object):
p[k] = v
return '?' + '&'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
def get_search_parameters(self, request):
# 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 = request.GET.has_key(ALL_VAR)
self.is_popup = request.GET.has_key(IS_POPUP_VAR)
self.params = dict(request.GET.items())
if self.params.has_key(PAGE_VAR):
del self.params[PAGE_VAR]
def get_results(self, request):
manager, lookup_params = self.manager, self.lookup_params
show_all, page_num = self.show_all, self.page_num
# Get the results.
paginator = ObjectPaginator(self.query_set, DEFAULT_RESULTS_PER_PAGE)
# Get the number of objects, with admin filters applied.
try:
paginator = ObjectPaginator(manager, lookup_params, DEFAULT_RESULTS_PER_PAGE)
# 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 Exception:
result_count = paginator.hits
# 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 filters applied.
real_lookup_params = lookup_params.copy()
del real_lookup_params['order_by']
if real_lookup_params:
full_result_count = manager.get_count()
# 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 isinstance(self.query_set._filters, models.Q) and not self.query_set._filters.kwargs:
full_result_count = result_count
else:
full_result_count = paginator.hits
del real_lookup_params
result_count = paginator.hits
full_result_count = self.model._default_manager.count()
can_show_all = result_count <= MAX_SHOW_ALL_ALLOWED
multi_page = result_count > DEFAULT_RESULTS_PER_PAGE
# Get the list of objects to display on this page.
if (show_all and can_show_all) or not multi_page:
result_list = manager.get_list(**lookup_params)
if (self.show_all and can_show_all) or not multi_page:
result_list = list(self.query_set)
else:
try:
result_list = paginator.get_page(page_num)
result_list = paginator.get_page(self.page_num)
except InvalidPage:
result_list = []
(self.result_count, self.full_result_count, self.result_list,
self.can_show_all, self.multi_page, self.paginator) = (result_count,
full_result_count, result_list, can_show_all, multi_page, paginator )
result_list = ()
def url_for_result(self, result):
return "%s/" % getattr(result, self.pk_attname)
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
@ -600,55 +598,64 @@ class ChangeList(object):
pass # Invalid ordering specified. Just use the default.
if params.has_key(ORDER_TYPE_VAR) and params[ORDER_TYPE_VAR] in ('asc', 'desc'):
order_type = params[ORDER_TYPE_VAR]
self.order_field, self.order_type = order_field, order_type
return order_field, order_type
def get_lookup_params(self):
# Prepare the lookup parameters for the API lookup.
(params, order_field, lookup_opts, order_type, opts, query) = \
(self.params, self.order_field, self.lookup_opts, self.order_type, self.opts, self.query)
lookup_params = params.copy()
def get_query_set(self):
qs = self.model._default_manager.get_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 lookup_params.has_key(i):
del lookup_params[i]
# If the order-by field is a field with a relationship, order by the value
# in the related table.
lookup_order_field = order_field
try:
f = lookup_opts.get_field(order_field)
except models.FieldDoesNotExist:
pass
# 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.lookup_opts.admin.list_select_related:
qs = qs.select_related()
else:
if isinstance(lookup_opts.get_field(order_field).rel, models.ManyToOne):
f = lookup_opts.get_field(order_field)
rel_ordering = f.rel.to._meta.ordering and f.rel.to._meta.ordering[0] or f.rel.to._meta.pk.column
lookup_order_field = '%s.%s' % (f.rel.to._meta.db_table, rel_ordering)
# Use select_related if one of the list_display options is a field with a
# relationship.
if lookup_opts.admin.list_select_related:
lookup_params['select_related'] = True
else:
for field_name in lookup_opts.admin.list_display:
for field_name in self.lookup_opts.admin.list_display:
try:
f = lookup_opts.get_field(field_name)
f = self.lookup_opts.get_field(field_name)
except models.FieldDoesNotExist:
pass
else:
if isinstance(f.rel, models.ManyToOne):
lookup_params['select_related'] = True
qs = qs.select_related()
break
lookup_params['order_by'] = ((order_type == 'desc' and '-' or '') + lookup_order_field,)
if lookup_opts.admin.search_fields and query:
complex_queries = []
for bit in query.split():
or_queries = []
for field_name in lookup_opts.admin.search_fields:
or_queries.append(models.Q(**{'%s__icontains' % field_name: bit}))
complex_queries.append(reduce(operator.or_, or_queries))
lookup_params['complex'] = reduce(operator.and_, complex_queries)
if opts.one_to_one_field:
lookup_params.update(opts.one_to_one_field.rel.limit_choices_to)
self.lookup_params = lookup_params
# Calculate lookup_order_field.
# If the order-by field is a field with a relationship, order by the
# value in the related table.
lookup_order_field = self.order_field
try:
f = self.lookup_opts.get_field(self.order_field, many_to_many=False)
except models.FieldDoesNotExist:
pass
else:
if isinstance(f.rel, models.ManyToOne):
rel_ordering = f.rel.to._meta.ordering and f.rel.to._meta.ordering[0] or f.rel.to._meta.pk.column
lookup_order_field = '%s.%s' % (f.rel.to._meta.db_table, rel_ordering)
# Set ordering.
qs = qs.order_by((self.order_type == 'desc' and '-' or '') + lookup_order_field)
# Apply keyword searches.
if self.lookup_opts.admin.search_fields and self.query:
for bit in self.query.split():
or_queries = [models.Q(**{'%s__icontains' % field_name: bit}) for field_name in self.lookup_opts.admin.search_fields]
other_qs = QuerySet(self.model)
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
qs = qs & other_qs
if self.opts.one_to_one_field:
qs = qs.filter(**self.opts.one_to_one_field.rel.limit_choices_to)
return qs
def url_for_result(self, result):
return "%s/" % getattr(result, self.pk_attname)
def change_list(request, app_label, model_name):
model = models.get_model(app_label, model_name)