1 from django.conf import settings
2 from django.contrib.admin.views.main import ALL_VAR, EMPTY_CHANGELIST_VALUE
3 from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR
4 from django.core.exceptions import ObjectDoesNotExist
5 from django.db import models
6 from django.utils import dateformat
7 from django.utils.html import escape, conditional_escape
8 from django.utils.text import capfirst
9 from django.utils.safestring import mark_safe
10 from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
11 from django.utils.encoding import smart_unicode, smart_str, force_unicode
12 from django.template import Library
13 import datetime
14
15 register = Library()
16
17 DOT = '.'
18
26 paginator_number = register.simple_tag(paginator_number)
27
29 paginator, page_num = cl.paginator, cl.page_num
30
31 pagination_required = (not cl.show_all or not cl.can_show_all) and cl.multi_page
32 if not pagination_required:
33 page_range = []
34 else:
35 ON_EACH_SIDE = 3
36 ON_ENDS = 2
37
38
39
40 if paginator.num_pages <= 10:
41 page_range = range(paginator.num_pages)
42 else:
43
44
45
46 page_range = []
47 if page_num > (ON_EACH_SIDE + ON_ENDS):
48 page_range.extend(range(0, ON_EACH_SIDE - 1))
49 page_range.append(DOT)
50 page_range.extend(range(page_num - ON_EACH_SIDE, page_num + 1))
51 else:
52 page_range.extend(range(0, page_num + 1))
53 if page_num < (paginator.num_pages - ON_EACH_SIDE - ON_ENDS - 1):
54 page_range.extend(range(page_num + 1, page_num + ON_EACH_SIDE + 1))
55 page_range.append(DOT)
56 page_range.extend(range(paginator.num_pages - ON_ENDS, paginator.num_pages))
57 else:
58 page_range.extend(range(page_num + 1, paginator.num_pages))
59
60 need_show_all_link = cl.can_show_all and not cl.show_all and cl.multi_page
61 return {
62 'cl': cl,
63 'pagination_required': pagination_required,
64 'show_all_url': need_show_all_link and cl.get_query_string({ALL_VAR: ''}),
65 'page_range': page_range,
66 'ALL_VAR': ALL_VAR,
67 '1': 1,
68 }
69 pagination = register.inclusion_tag('admin/pagination.html')(pagination)
70
72 lookup_opts = cl.lookup_opts
73
74 for i, field_name in enumerate(lookup_opts.admin.list_display):
75 try:
76 f = lookup_opts.get_field(field_name)
77 admin_order_field = None
78 except models.FieldDoesNotExist:
79
80
81
82 if field_name == '__unicode__':
83 header = force_unicode(lookup_opts.verbose_name)
84 elif field_name == '__str__':
85 header = smart_str(lookup_opts.verbose_name)
86 else:
87 attr = getattr(cl.model, field_name)
88 try:
89 header = attr.short_description
90 except AttributeError:
91 header = field_name.replace('_', ' ')
92
93
94 admin_order_field = getattr(getattr(cl.model, field_name), "admin_order_field", None)
95 if not admin_order_field:
96 yield {"text": header}
97 continue
98
99
100
101 else:
102 if isinstance(f.rel, models.ManyToOneRel) and f.null:
103 yield {"text": f.verbose_name}
104 continue
105 else:
106 header = f.verbose_name
107
108 th_classes = []
109 new_order_type = 'asc'
110 if field_name == cl.order_field or admin_order_field == cl.order_field:
111 th_classes.append('sorted %sending' % cl.order_type.lower())
112 new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
113
114 yield {"text": header,
115 "sortable": True,
116 "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
117 "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
118
120 BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
121 return mark_safe(u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val))
122
124 first = True
125 pk = cl.lookup_opts.pk.attname
126 for field_name in cl.lookup_opts.admin.list_display:
127 row_class = ''
128 try:
129 f = cl.lookup_opts.get_field(field_name)
130 except models.FieldDoesNotExist:
131
132
133 try:
134 attr = getattr(result, field_name)
135 allow_tags = getattr(attr, 'allow_tags', False)
136 boolean = getattr(attr, 'boolean', False)
137 if callable(attr):
138 attr = attr()
139 if boolean:
140 allow_tags = True
141 result_repr = _boolean_icon(attr)
142 else:
143 result_repr = smart_unicode(attr)
144 except (AttributeError, ObjectDoesNotExist):
145 result_repr = EMPTY_CHANGELIST_VALUE
146 else:
147
148
149 if not allow_tags:
150 result_repr = escape(result_repr)
151 else:
152 result_repr = mark_safe(result_repr)
153 else:
154 field_val = getattr(result, f.attname)
155
156 if isinstance(f.rel, models.ManyToOneRel):
157 if field_val is not None:
158 result_repr = escape(getattr(result, f.name))
159 else:
160 result_repr = EMPTY_CHANGELIST_VALUE
161
162 elif isinstance(f, models.DateField) or isinstance(f, models.TimeField):
163 if field_val:
164 (date_format, datetime_format, time_format) = get_date_formats()
165 if isinstance(f, models.DateTimeField):
166 result_repr = capfirst(dateformat.format(field_val, datetime_format))
167 elif isinstance(f, models.TimeField):
168 result_repr = capfirst(dateformat.time_format(field_val, time_format))
169 else:
170 result_repr = capfirst(dateformat.format(field_val, date_format))
171 else:
172 result_repr = EMPTY_CHANGELIST_VALUE
173 row_class = ' class="nowrap"'
174
175 elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
176 result_repr = _boolean_icon(field_val)
177
178 elif isinstance(f, models.DecimalField):
179 if field_val is not None:
180 result_repr = ('%%.%sf' % f.decimal_places) % field_val
181 else:
182 result_repr = EMPTY_CHANGELIST_VALUE
183
184
185 elif f.choices:
186 result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
187 else:
188 result_repr = escape(field_val)
189 if force_unicode(result_repr) == '':
190 result_repr = mark_safe(' ')
191
192 if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
193 table_tag = {True:'th', False:'td'}[first]
194 first = False
195