Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

MERGED NEW-ADMIN BRANCH (except for po/mo files, which will come in a…

… separate commit)

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1434 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9dda4abee1225db7a7b195b84c915fdd141a7260 1 parent 4fe5c9b
@adrianholovaty adrianholovaty authored
Showing with 2,062 additions and 1,125 deletions.
  1. +8 −8 django/bin/validate.py
  2. +152 −0 django/contrib/admin/filterspecs.py
  3. +75 −0 django/contrib/admin/templates/admin/change_form.html
  4. +20 −0 django/contrib/admin/templates/admin/change_list.html
  5. +13 −0 django/contrib/admin/templates/admin/change_list_results.html
  6. +10 −0 django/contrib/admin/templates/admin/date_hierarchy.html
  7. +15 −0 django/contrib/admin/templates/admin/edit_inline_stacked.html
  8. +42 −0 django/contrib/admin/templates/admin/edit_inline_tabular.html
  9. +21 −0 django/contrib/admin/templates/admin/field_line.html
  10. +7 −0 django/contrib/admin/templates/admin/filter.html
  11. +5 −0 django/contrib/admin/templates/admin/filters.html
  12. +9 −0 django/contrib/admin/templates/admin/pagination.html
  13. +14 −0 django/contrib/admin/templates/admin/search_form.html
  14. +8 −0 django/contrib/admin/templates/admin/submit_line.html
  15. +12 −10 django/contrib/admin/templates/admin_doc/bookmarklets.html
  16. +4 −0 django/contrib/admin/templates/widget/date_time.html
  17. +1 −0  django/contrib/admin/templates/widget/default.html
  18. +4 −0 django/contrib/admin/templates/widget/file.html
  19. +7 −0 django/contrib/admin/templates/widget/foreign.html
  20. +1 −0  django/contrib/admin/templates/widget/many_to_many.html
  21. +278 −0 django/contrib/admin/templatetags/admin_list.py
  22. +258 −0 django/contrib/admin/templatetags/admin_modify.py
  23. +431 −876 django/contrib/admin/views/main.py
  24. +130 −24 django/core/formfields.py
  25. +3 −3 django/core/management.py
  26. +307 −145 django/core/meta/__init__.py
  27. +188 −25 django/core/meta/fields.py
  28. +29 −26 django/models/__init__.py
  29. +9 −8 django/views/generic/create_update.py
  30. +1 −0  setup.py
View
16 django/bin/validate.py
@@ -16,19 +16,19 @@ def validate_class(klass):
assert isinstance(f.rel, meta.ManyToMany), \
"ManyToManyField %s should have 'rel' set to a ManyToMany instance." % f.name
# Inline related objects.
- for rel_opts, rel_field in opts.get_inline_related_objects():
- assert len([f for f in rel_opts.fields if f.core]) > 0, \
+ for related in opts.get_followed_related_objects():
+ assert len([f for f in related.opts.fields if f.core]) > 0, \
"At least one field in %s should have core=True, because it's being edited inline by %s." % \
- (rel_opts.object_name, opts.object_name)
+ (related.opts.object_name, opts.object_name)
# All related objects.
related_apps_seen = []
- for rel_opts, rel_field in opts.get_all_related_objects():
- if rel_opts in related_apps_seen:
- assert rel_field.rel.related_name is not None, \
+ for related in opts.get_all_related_objects():
+ if related.opts in related_apps_seen:
+ assert related.field.rel.related_name is not None, \
"Relationship in field %s.%s needs to set 'related_name' because more than one" \
" %s object is referenced in %s." % \
- (rel_opts.object_name, rel_field.name, opts.object_name, rel_opts.object_name)
- related_apps_seen.append(rel_opts)
+ (related.opts.object_name, related.field.name, opts.object_name, rel_opts.object_name)
+ related_apps_seen.append(related.opts)
# Etc.
if opts.admin is not None:
assert opts.admin.ordering or opts.ordering, \
View
152 django/contrib/admin/filterspecs.py
@@ -0,0 +1,152 @@
+"""
+FilterSpec encapsulates the logic for displaying filters in the Django admin.
+Filters are specified in models with the "list_filter" option.
+
+Each filter subclass knows how to display a filter for a field that passes a
+certain test -- e.g. being a DateField or ForeignKey.
+"""
+
+from django.core import meta
+import datetime
+
+class FilterSpec(object):
+ filter_specs = []
+ def __init__(self, f, request, params):
+ self.field = f
+ self.params = params
+
+ def register(cls, test, factory):
+ cls.filter_specs.append( (test, factory) )
+ register = classmethod(register)
+
+ def create(cls, f, request, params):
+ for test, factory in cls.filter_specs:
+ if test(f):
+ return factory(f, request, params)
+ create = classmethod(create)
+
+ def has_output(self):
+ return True
+
+ def choices(self, cl):
+ raise NotImplementedError()
+
+ def title(self):
+ return self.field.verbose_name
+
+ def output(self, cl):
+ t = []
+ if self.has_output():
+ t.append(_('<h3>By %s:</h3>\n<ul>\n') % self.title())
+
+ for choice in self.choices(cl):
+ t.append('<li%s><a href="%s">%s</a></li>\n' % \
+ ((choice['selected'] and ' class="selected"' or ''),
+ choice['query_string'] ,
+ choice['display']))
+ t.append('</ul>\n\n')
+ return "".join(t)
+
+class RelatedFilterSpec(FilterSpec):
+ def __init__(self, f, request, params):
+ super(RelatedFilterSpec, self).__init__(f, request, params)
+ if isinstance(f, meta.ManyToManyField):
+ self.lookup_title = f.rel.to.verbose_name
+ else:
+ self.lookup_title = f.verbose_name
+ self.lookup_kwarg = '%s__%s__exact' % (f.name, f.rel.to.pk.name)
+ self.lookup_val = request.GET.get(self.lookup_kwarg, None)
+ self.lookup_choices = f.rel.to.get_model_module().get_list()
+
+ def has_output(self):
+ return len(self.lookup_choices) > 1
+
+ def title(self):
+ return self.lookup_title
+
+ def choices(self, cl):
+ yield {'selected': self.lookup_val is None,
+ 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
+ 'display': _('All')}
+ for val in self.lookup_choices:
+ pk_val = getattr(val, self.field.rel.to.pk.attname)
+ yield {'selected': self.lookup_val == str(pk_val),
+ 'query_string': cl.get_query_string( {self.lookup_kwarg: pk_val}),
+ 'display': val}
+
+FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
+
+class ChoicesFilterSpec(FilterSpec):
+ def __init__(self, f, request, params):
+ super(ChoicesFilterSpec, self).__init__(f, request, params)
+ self.lookup_kwarg = '%s__exact' % f.name
+ self.lookup_val = request.GET.get(self.lookup_kwarg, None)
+
+ def choices(self, cl):
+ yield {'selected': self.lookup_val is None,
+ 'query_string': cl.get_query_string( {}, [self.lookup_kwarg]),
+ 'display': _('All')}
+ for k, v in self.field.choices:
+ yield {'selected': str(k) == self.lookup_val,
+ 'query_string': cl.get_query_string( {self.lookup_kwarg: k}),
+ 'display': v}
+
+FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
+
+class DateFieldFilterSpec(FilterSpec):
+ def __init__(self, f, request, params):
+ super(DateFieldFilterSpec, self).__init__(f, request, params)
+
+ self.field_generic = '%s__' % self.field.name
+
+ self.date_params = dict([(k, v) for k, v in params.items() if k.startswith(self.field_generic)])
+
+ today = datetime.date.today()
+ one_week_ago = today - datetime.timedelta(days=7)
+ today_str = isinstance(self.field, meta.DateTimeField) and today.strftime('%Y-%m-%d 23:59:59') or today.strftime('%Y-%m-%d')
+
+ self.links = (
+ (_('Any date'), {}),
+ (_('Today'), {'%s__year' % self.field.name: str(today.year),
+ '%s__month' % self.field.name: str(today.month),
+ '%s__day' % self.field.name: str(today.day)}),
+ (_('Past 7 days'), {'%s__gte' % self.field.name: one_week_ago.strftime('%Y-%m-%d'),
+ '%s__lte' % f.name: today_str}),
+ (_('This month'), {'%s__year' % self.field.name: str(today.year),
+ '%s__month' % f.name: str(today.month)}),
+ (_('This year'), {'%s__year' % self.field.name: str(today.year)})
+ )
+
+ def title(self):
+ return self.field.verbose_name
+
+ def choices(self, cl):
+ for title, param_dict in self.links:
+ yield {'selected': self.date_params == param_dict,
+ 'query_string': cl.get_query_string( param_dict, self.field_generic),
+ 'display': title}
+
+FilterSpec.register(lambda f: isinstance(f, meta.DateField), DateFieldFilterSpec)
+
+class BooleanFieldFilterSpec(FilterSpec):
+ def __init__(self, f, request, params):
+ super(BooleanFieldFilterSpec, self).__init__(f, request, params)
+ self.lookup_kwarg = '%s__exact' % f.name
+ self.lookup_kwarg2 = '%s__isnull' % f.name
+ self.lookup_val = request.GET.get(self.lookup_kwarg, None)
+ self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
+
+ def title(self):
+ return self.field.verbose_name
+
+ def choices(self, cl):
+ for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
+ yield {'selected': self.lookup_val == v and not self.lookup_val2,
+ 'query_string': cl.get_query_string( {self.lookup_kwarg: v}, [self.lookup_kwarg2]),
+ 'display': k}
+ if isinstance(self.field, meta.NullBooleanField):
+ yield {'selected': self.lookup_val2 == 'True',
+ 'query_string': cl.get_query_string( {self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
+ 'display': _('Unknown')}
+
+FilterSpec.register(lambda f: isinstance(f, meta.BooleanField) or isinstance(f, meta.NullBooleanField), BooleanFieldFilterSpec)
View
75 django/contrib/admin/templates/admin/change_form.html
@@ -0,0 +1,75 @@
+{% extends "admin/base_site" %}
+{% load i18n %}
+{% load admin_modify %}
+{% load adminmedia %}
+{% block extrahead %}
+{% for js in bound_manipulator.javascript_imports %}{% include_admin_script js %}{% endfor %}
+{% endblock %}
+{% block coltype %}{{ bound_manipulator.coltype }}{% endblock %}
+{% block bodyclass %}{{ app_label }}-{{ bound_manipulator.object_name.lower }} change-form{% endblock %}
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+ <a href="../../../">{% trans "Home" %}</a> &rsaquo;
+ <a href="../">{{ bound_manipulator.verbose_name_plural|capfirst }}</a> &rsaquo;
+ {% if add %}{% trans "Add" %} {{ bound_manipulator.verbose_name }}{% else %}{{ bound_manipulator.original|striptags|truncatewords:"18" }}{% endif %}
+</div>
+{% endif %}{% endblock %}
+{% block content %}<div id="content-main">
+{% if change %}{% if not is_popup %}
+ <ul class="object-tools"><li><a href="history/" class="historylink">{% trans "History" %}</a></li>
+ {% if bound_manipulator.has_absolute_url %}<li><a href="/r/{{ bound_manipulator.content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
+ </ul>
+{% endif %}{% endif %}
+<form {{ bound_manipulator.form_enc_attrib }} action='{{ form_url }}' method="post">{% block form_top %}{% endblock %}
+{% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}
+{% if bound_manipulator.save_on_top %}{% submit_row bound_manipulator %}{% endif %}
+{% if form.error_dict %}
+ <p class="errornote">
+ {% blocktrans count form.error_dict.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+ </p>
+{% endif %}
+{% for bound_field_set in bound_manipulator.bound_field_sets %}
+ <fieldset class="module aligned {{ bound_field_set.classes }}">
+ {% if bound_field_set.name %}<h2>{{ bound_field_set.name }}</h2>{% endif %}
+ {% for bound_field_line in bound_field_set %}
+ {% admin_field_line bound_field_line %}
+ {% for bound_field in bound_field_line %}
+ {% filter_interface_script_maybe bound_field %}
+ {% endfor %}
+ {% endfor %}
+ </fieldset>
+{% endfor %}
+{% block after_field_sets %}{% endblock %}
+{% if change %}
+ {% if bound_manipulator.ordered_objects %}
+ <fieldset class="module"><h2>{% trans "Ordering" %}</h2>
+ <div class="form-row{% if form.order_.errors %} error{% endif %} ">
+ {% if form.order_.errors %}{{ form.order_.html_error_list }}{% endif %}
+ <p><label for="id_order_">{% trans "Order:" %}</label> {{ form.order_ }}</p>
+ </div></fieldset>
+ {% endif %}
+{% endif %}
+{% for related_object in bound_manipulator.inline_related_objects %}{% edit_inline related_object %}{% endfor %}
+{% block after_related_objects %}{% endblock %}
+{% submit_row bound_manipulator %}
+{% if add %}
+ <script type="text/javascript">document.getElementById("{{ bound_manipulator.first_form_field_id }}").focus();</script>
+{% endif %}
+{% if bound_manipulator.auto_populated_fields %}
+ <script type="text/javascript">
+ {% auto_populated_field_script bound_manipulator.auto_populated_fields change %}
+ </script>
+{% endif %}
+{% if change %}
+ {% if bound_manipulator.ordered_objects %}
+ {% if form.order_objects %}<ul id="orderthese">
+ {% for object in form.order_objects %}
+ <li id="p{% object_pk bound_manipulator object %}">
+ <span id="handlep{% object_pk bound_manipulator object %}">{{ object|truncatewords:"5" }}</span>
+ </li>
+ {% endfor %}
+ </ul>{% endif %}
+ {% endif %}
+{% endif %}
+</form></div>
+{% endblock %}
View
20 django/contrib/admin/templates/admin/change_list.html
@@ -0,0 +1,20 @@
+{% load admin_list %}
+{% load i18n %}
+{% extends "admin/base_site" %}
+{% block bodyclass %}change-list{% endblock %}
+{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; {{ cl.opts.verbose_name_plural|capfirst }} </div>{% endblock %}{% endif %}
+{% block coltype %}flex{% endblock %}
+{% block content %}
+<div id="content-main">
+{% if has_add_permission %}
+<ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}</a></li></ul>
+{% endif %}
+<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
+{% search_form cl %}
+{% date_hierarchy cl %}
+{% filters cl %}
+{% result_list cl %}
+{% pagination cl %}
+</div>
+</div>
+{% endblock %}
View
13 django/contrib/admin/templates/admin/change_list_results.html
@@ -0,0 +1,13 @@
+<table cellspacing="0">
+<thead>
+<tr>
+{% for header in result_headers %}<th{{ header.class_attrib }}>
+{% if header.sortable %}<a href="{{ header.url }}">{% endif %}
+{{ header.text|capfirst }}
+{% if header.sortable %}</a>{% endif %}</th>{% endfor %}
+</tr>
+</thead>
+{% for result in results %}
+<tr class="{% cycle row1,row2 %}">{% for item in result %}{{ item }}{% endfor %}</tr>
+{% endfor %}
+</table>
View
10 django/contrib/admin/templates/admin/date_hierarchy.html
@@ -0,0 +1,10 @@
+{% if show %}
+<div class="xfull">
+<ul class="toplinks">
+{% if back %}<li class="date-back"><a href="{{ back.link }}">&lsaquo; {{ back.title }}</a></li>{% endif %}
+{% for choice in choices %}
+<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title }}{% if choice.link %}</a>{% endif %}</li>
+{% endfor %}
+</ul><br class="clear" />
+</div>
+{% endif %}
View
15 django/contrib/admin/templates/admin/edit_inline_stacked.html
@@ -0,0 +1,15 @@
+<fieldset class="module aligned">
+ {% for fcw in bound_related_object.form_field_collection_wrappers %}
+ <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }}&nbsp;#{{ forloop.counter }}</h2>
+ {% if bound_related_object.show_url %}{% if fcw.obj.original %}
+ <p><a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a></p>
+ {% endif %}{% endif %}
+ {% for bound_field in fcw.bound_fields %}
+ {% if bound_field.hidden %}
+ {% field_widget bound_field %}
+ {% else %}
+ {% admin_field_line bound_field %}
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+</fieldset>
View
42 django/contrib/admin/templates/admin/edit_inline_tabular.html
@@ -0,0 +1,42 @@
+<fieldset class="module">
+ <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2><table>
+ <thead><tr>
+ {% for fw in bound_related_object.field_wrapper_list %}
+ {% if fw.needs_header %}
+ <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst }}</th>
+ {% endif %}
+ {% endfor %}
+ {% for fcw in bound_related_object.form_field_collection_wrappers %}
+ {% if change %}{% if original_row_needed %}
+ {% if fcw.obj.original %}
+ <tr class="row-label {% cycle row1,row2 %}"><td colspan="{{ num_headers }}"><strong>{{ fcw.obj.original }}</strong></tr>
+ {% endif %}
+ {% endif %}{% endif %}
+ {% if fcw.obj.errors %}
+ <tr class="errorlist"><td colspan="{{ num_headers }}">
+ {{ fcw.obj.html_combined_error_list }}
+ </tr>
+ {% endif %}
+ <tr class="{% cycle row1,row2 %}">
+ {% for bound_field in fcw.bound_fields %}
+ {% if not bound_field.hidden %}
+ <td {{ bound_field.cell_class_attribute }}>
+ {% field_widget bound_field %}
+ </td>
+ {% endif %}
+ {% endfor %}
+ {% if bound_related_object.show_url %}<td>
+ {% if fcw.obj.original %}<a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a>{% endif %}
+ </td>{% endif %}
+ </tr>
+
+ {% endfor %} </table>
+
+ {% for fcw in bound_related_object.form_field_collection_wrappers %}
+ {% for bound_field in fcw.bound_fields %}
+ {% if bound_field.hidden %}
+ {% field_widget bound_field %}
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+</fieldset>
View
21 django/contrib/admin/templates/admin/field_line.html
@@ -0,0 +1,21 @@
+<div class="{{ class_names }}" >
+{% for bound_field in bound_fields %}{{ bound_field.html_error_list }}{% endfor %}
+{% for bound_field in bound_fields %}
+ {% if bound_field.has_label_first %}
+ {% field_label bound_field %}
+ {% endif %}
+ {% field_widget bound_field %}
+ {% if not bound_field.has_label_first %}
+ {% field_label bound_field %}
+ {% endif %}
+ {% if change %}
+ {% if bound_field.field.primary_key %}
+ {{ bound_field.original_value }}
+ {% endif %}
+ {% if bound_field.raw_id_admin %}
+ {% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %}
+ {% endif %}
+ {% endif %}
+ {% if bound_field.field.help_text %}<p class="help">{{ bound_field.field.help_text }}</p>{% endif %}
+{% endfor %}
+</div>
View
7 django/contrib/admin/templates/admin/filter.html
@@ -0,0 +1,7 @@
+<h3>{% blocktrans %} By {{ title }} {% endblocktrans %}</h3>
+<ul>
+{% for choice in choices %}
+ <li{% if choice.selected %} class="selected"{% endif %}>
+ <a href="{{ choice.query_string }}">{{ choice.display }}</a></li>
+{% endfor %}
+</ul>
View
5 django/contrib/admin/templates/admin/filters.html
@@ -0,0 +1,5 @@
+{% if cl.has_filters %}<div id="changelist-filter">
+<h2>Filter</h2>
+{% for spec in cl.filter_specs %}
+ {% filter cl spec %}
+{% endfor %}</div>{% endif %}
View
9 django/contrib/admin/templates/admin/pagination.html
@@ -0,0 +1,9 @@
+<p class="paginator">
+{% if pagination_required %}
+{% for i in page_range %}
+ {% paginator_number cl i %}
+{% endfor %}
+{% endif %}
+{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
+{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">Show all</a>{% endif %}
+</p>
View
14 django/contrib/admin/templates/admin/search_form.html
@@ -0,0 +1,14 @@
+{% if cl.lookup_opts.admin.search_fields %}
+<div id="toolbar"><form id="changelist-search" action="" method="get">
+<label><img src="{% admin_media_prefix %}img/admin/icon_searchbox.png" /></label>
+<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query|escape }}" id="searchbar" />
+<input type="submit" value="Go" />
+{% if show_result_count %}
+ <span class="small quiet">{{ cl.result_count }} result{{ cl.result_count|pluralize }} (<a href="?">{{ cl.full_result_count }} total</a>)</span>
+{% endif %}
+{% for pair in cl.params.items %}
+ {% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0|escape }}" value="{{ pair.1|escape }}"/>{% endifnotequal %}
+{% endfor %}
+</form></div>
+<script type="text/javascript">document.getElementById("searchbar").focus();</script>
+{% endif %}
View
8 django/contrib/admin/templates/admin/submit_line.html
@@ -0,0 +1,8 @@
+{% load i18n %}
+<div class="submit-row">
+{% if show_delete_link %}<p class="float-left"><a href="delete/" class="deletelink">{% trans "Delete" %}</a></p>{% endif %}
+{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" {{ onclick_attrib }}/>{%endif%}
+{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" {{ onclick_attrib }} />{% endif %}
+{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" {{ onclick_attrib }}/>{% endif %}
+{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" {{ onclick_attrib }}/>{% endif %}
+</div>
View
22 django/contrib/admin/templates/admin_doc/bookmarklets.html
@@ -1,30 +1,32 @@
{% extends "admin/base_site" %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Bookmarklets</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; <a href="../">{% trans "Documentation" %}</a> &rsaquo; {% trans "Bookmarklets" %}</div>{% endblock %}
-{% block title %}Documentation bookmarklets{% endblock %}
+{% block title %}{% trans "Documentation bookmarklets" %}{% endblock %}
{% block content %}
+{% blocktrans %}
<p class="help">To install bookmarklets, drag the link to your bookmarks
toolbar, or right-click the link and add it to your bookmarks. Now you can
select the bookmarklet from any page in the site. Note that some of these
bookmarklets require you to be viewing the site from a computer designated
as "internal" (talk to your system administrator if you aren't sure if
your computer is "internal").</p>
+{% endblocktrans %}
<div id="content-main">
- <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('HEAD',location.href,false);x.send(null);try{view=x.getResponseHeader('x-view');}catch(e){alert('No view found for this page');return;}if(view=="undefined"){alert("No view found for this page");}document.location='{{ admin_url }}/doc/views/'+view+'/';})()">Documentation for this page</a></h3>
- <p>Jumps you from any page to the documentation for the view that generates that page.</p>
+ <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('HEAD',location.href,false);x.send(null);try{view=x.getResponseHeader('x-view');}catch(e){alert('No view found for this page');return;}if(view=="undefined"){alert("No view found for this page");}document.location='{{ admin_url }}/doc/views/'+view+'/';})()">{% trans "Documentation for this page" %}</a></h3>
+ <p>{% trans "Jumps you from any page to the documentation for the view that generates that page." %}</p>
- <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{type=x.getResponseHeader('x-object-type');id=x.getResponseHeader('x-object-id');}catch(e){type='(none)';id='(none)';}d=document;b=d.body;e=d.createElement('div');e.id='xxxhhh';s=e.style;s.position='absolute';s.left='10px';s.top='10px';s.font='10px monospace';s.border='1px black solid';s.padding='4px';s.backgroundColor='#eee';e.appendChild(d.createTextNode('Type: '+type));e.appendChild(d.createElement('br'));e.appendChild(d.createTextNode('ID: '+id));e.appendChild(d.createElement('br'));l=d.createElement('a');l.href='#';l.onclick=function(){b.removeChild(e);};l.appendChild(d.createTextNode('[close]'));l.style.textDecoration='none';e.appendChild(l);b.appendChild(e);})();">Show object ID</a></h3>
- <p>Shows the content-type and unique ID for pages that represent a single object.</p>
+ <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{type=x.getResponseHeader('x-object-type');id=x.getResponseHeader('x-object-id');}catch(e){type='(none)';id='(none)';}d=document;b=d.body;e=d.createElement('div');e.id='xxxhhh';s=e.style;s.position='absolute';s.left='10px';s.top='10px';s.font='10px monospace';s.border='1px black solid';s.padding='4px';s.backgroundColor='#eee';e.appendChild(d.createTextNode('Type: '+type));e.appendChild(d.createElement('br'));e.appendChild(d.createTextNode('ID: '+id));e.appendChild(d.createElement('br'));l=d.createElement('a');l.href='#';l.onclick=function(){b.removeChild(e);};l.appendChild(d.createTextNode('[close]'));l.style.textDecoration='none';e.appendChild(l);b.appendChild(e);})();">{% trans "Show object ID" %}</a></h3>
+ <p>{% trans "Shows the content-type and unique ID for pages that represent a single object." %}</p>
- <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){var x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){var x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{var type=x.getResponseHeader('x-object-type');var id=x.getResponseHeader('x-object-id');}catch(e){return;}document.location='{{ admun_url }}/'+type.split('.').join('/')+'/'+id+'/';})()">Edit this object (current window)</a></h3>
- <p>Jumps to the admin page for pages that represent a single object.</p>
+ <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){var x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){var x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{var type=x.getResponseHeader('x-object-type');var id=x.getResponseHeader('x-object-id');}catch(e){return;}document.location='{{ admun_url }}/'+type.split('.').join('/')+'/'+id+'/';})()">{% trans "Edit this object (current window)" %}</a></h3>
+ <p>{% trans "Jumps to the admin page for pages that represent a single object." %}</p>
- <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){var x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){var x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{var type=x.getResponseHeader('x-object-type');var id=x.getResponseHeader('x-object-id');}catch(e){return;}window.open('{{ admun_url }}/'+type.split('.').join('/')+'/'+id+'/');})()">Edit this object (new window)</a></h3>
- <p>As above, but opens the admin page in a new window.</p>
+ <h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){var x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){var x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{var type=x.getResponseHeader('x-object-type');var id=x.getResponseHeader('x-object-id');}catch(e){return;}window.open('{{ admun_url }}/'+type.split('.').join('/')+'/'+id+'/');})()">{% trans "Edit this object (new window)" %}</a></h3>
+ <p>{% trans "As above, but opens the admin page in a new window." %}</p>
</div>
{% endblock %}
View
4 django/contrib/admin/templates/widget/date_time.html
@@ -0,0 +1,4 @@
+<p class="datetime">
+ Date: {{ bound_field.form_fields.0 }}<br />
+ Time: {{ bound_field.form_fields.1 }}
+</p>
View
1  django/contrib/admin/templates/widget/default.html
@@ -0,0 +1 @@
+{% output_all bound_field.form_fields %}
View
4 django/contrib/admin/templates/widget/file.html
@@ -0,0 +1,4 @@
+{% if bound_field.original_value %}
+Currently: <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value }} </a><br />
+Change: {% output_all bound_field.form_fields %}
+{% else %} {% output_all bound_field.form_fields %} {% endif %}
View
7 django/contrib/admin/templates/widget/foreign.html
@@ -0,0 +1,7 @@
+{% output_all bound_field.form_fields %}
+{% if bound_field.raw_id_admin %}
+ <a href="../../../{{ bound_field.field.rel.to.app_label }}/{{ bound_field.field.rel.to.module_name }}/" class="related-lookup" id="lookup_{{bound_field.element_id}}" onclick="return showRelatedObjectLookupPopup(this);"> <img src="{% admin_media_prefix %}img/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>
+{% else %}
+{% if bound_field.needs_add_label %}
+ <a href="../../../{{ bound_field.field.rel.to.app_label }}/{{ bound_field.field.rel.to.module_name }}/add/" class="add-another" id="add_{{ bound_field.element_id}}" onclick="return showAddAnotherPopup(this);"> <img src="{% admin_media_prefix %}img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>
+{% endif %} {% endif %}
View
1  django/contrib/admin/templates/widget/many_to_many.html
@@ -0,0 +1 @@
+{% include "widget/foreign" %}
View
278 django/contrib/admin/templatetags/admin_list.py
@@ -0,0 +1,278 @@
+from django.contrib.admin.views.main import MAX_SHOW_ALL_ALLOWED, DEFAULT_RESULTS_PER_PAGE, ALL_VAR
+from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR
+from django.contrib.admin.views.main import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE, MONTHS
+from django.core import meta, template
+from django.core.exceptions import ObjectDoesNotExist
+from django.core.template.decorators import simple_tag, inclusion_tag
+from django.utils import dateformat
+from django.utils.html import strip_tags, escape
+from django.utils.text import capfirst
+from django.utils.translation import get_date_formats
+from django.conf.settings import ADMIN_MEDIA_PREFIX
+
+DOT = '.'
+
+#@simple_tag
+def paginator_number(cl,i):
+ if i == DOT:
+ return '... '
+ elif i == cl.page_num:
+ return '<span class="this-page">%d</span> ' % (i+1)
+ else:
+ return '<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
+paginator_number = simple_tag(paginator_number)
+
+#@inclusion_tag('admin/pagination')
+def pagination(cl):
+ paginator, page_num = cl.paginator, cl.page_num
+
+ pagination_required = (not cl.show_all or not cl.can_show_all) and cl.multi_page
+ if not pagination_required:
+ page_range = []
+ else:
+ ON_EACH_SIDE = 3
+ ON_ENDS = 2
+
+ # If there are 10 or fewer pages, display links to every page.
+ # Otherwise, do some fancy
+ if paginator.pages <= 10:
+ page_range = range(paginator.pages)
+ else:
+ # Insert "smart" pagination links, so that there are always ON_ENDS
+ # links at either end of the list of pages, and there are always
+ # ON_EACH_SIDE links at either end of the "current page" link.
+ page_range = []
+ if page_num > (ON_EACH_SIDE + ON_ENDS):
+ page_range.extend(range(0, ON_EACH_SIDE - 1))
+ page_range.append(DOT)
+ page_range.extend(range(page_num - ON_EACH_SIDE, page_num + 1))
+ else:
+ page_range.extend(range(0, page_num + 1))
+ if page_num < (paginator.pages - ON_EACH_SIDE - ON_ENDS - 1):
+ page_range.extend(range(page_num + 1, page_num + ON_EACH_SIDE + 1))
+ page_range.append(DOT)
+ page_range.extend(range(paginator.pages - ON_ENDS, paginator.pages))
+ else:
+ page_range.extend(range(page_num + 1, paginator.pages))
+
+ need_show_all_link = cl.can_show_all and not cl.show_all and cl.multi_page
+ return {
+ 'cl': cl,
+ 'pagination_required': pagination_required,
+ 'show_all_url': need_show_all_link and cl.get_query_string({ALL_VAR: ''}),
+ 'page_range': page_range,
+ 'ALL_VAR': ALL_VAR,
+ '1': 1,
+ }
+pagination = inclusion_tag('admin/pagination')(pagination)
+
+def result_headers(cl):
+ lookup_opts = cl.lookup_opts
+
+ for i, field_name in enumerate(lookup_opts.admin.list_display):
+ try:
+ f = lookup_opts.get_field(field_name)
+ except meta.FieldDoesNotExist:
+ # For non-field list_display values, check for the function
+ # attribute "short_description". If that doesn't exist, fall
+ # back to the method name. And __repr__ is a special-case.
+ if field_name == '__repr__':
+ header = lookup_opts.verbose_name
+ else:
+ func = getattr(cl.mod.Klass, field_name) # Let AttributeErrors propogate.
+ try:
+ header = func.short_description
+ except AttributeError:
+ header = func.__name__.replace('_', ' ')
+ # Non-field list_display values don't get ordering capability.
+ yield {"text": header}
+ else:
+ if isinstance(f.rel, meta.ManyToOne) and f.null:
+ yield {"text": f.verbose_name}
+ else:
+ th_classes = []
+ new_order_type = 'asc'
+ if field_name == cl.order_field:
+ th_classes.append('sorted %sending' % cl.order_type.lower())
+ new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
+
+ yield {"text": f.verbose_name,
+ "sortable": True,
+ "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
+ "class_attrib": (th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
+
+def items_for_result(cl, result):
+ first = True
+ pk = cl.lookup_opts.pk.attname
+ for field_name in cl.lookup_opts.admin.list_display:
+ row_class = ''
+ try:
+ f = cl.lookup_opts.get_field(field_name)
+ except meta.FieldDoesNotExist:
+ # For non-field list_display values, the value is a method
+ # name. Execute the method.
+ try:
+ func = getattr(result, field_name)
+ result_repr = str(func())
+ except AttributeError, ObjectDoesNotExist:
+ result_repr = EMPTY_CHANGELIST_VALUE
+ else:
+ # Strip HTML tags in the resulting text, except if the
+ # function has an "allow_tags" attribute set to True.
+ if not getattr(func, 'allow_tags', False):
+ result_repr = strip_tags(result_repr)
+ else:
+ field_val = getattr(result, f.attname)
+
+ if isinstance(f.rel, meta.ManyToOne):
+ if field_val is not None:
+ result_repr = getattr(result, 'get_%s' % f.name)()
+ else:
+ result_repr = EMPTY_CHANGELIST_VALUE
+ # Dates and times are special: They're formatted in a certain way.
+ elif isinstance(f, meta.DateField) or isinstance(f, meta.TimeField):
+ if field_val:
+ (date_format, datetime_format, time_format) = get_date_formats()
+ if isinstance(f, meta.DateTimeField):
+ result_repr = capfirst(dateformat.format(field_val, datetime_format))
+ elif isinstance(f, meta.TimeField):
+ result_repr = capfirst(dateformat.time_format(field_val, time_format))
+ else:
+ result_repr = capfirst(dateformat.format(field_val, date_format))
+ else:
+ result_repr = EMPTY_CHANGELIST_VALUE
+ row_class = ' class="nowrap"'
+ # Booleans are special: We use images.
+ elif isinstance(f, meta.BooleanField) or isinstance(f, meta.NullBooleanField):
+ BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
+ result_repr = '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
+ # ImageFields are special: Use a thumbnail.
+ elif isinstance(f, meta.ImageField):
+ from django.parts.media.photos import get_thumbnail_url
+ result_repr = '<img src="%s" alt="%s" title="%s" />' % (get_thumbnail_url(getattr(result, 'get_%s_url' % f.name)(), '120'), field_val, field_val)
+ # FloatFields are special: Zero-pad the decimals.
+ elif isinstance(f, meta.FloatField):
+ if field_val is not None:
+ result_repr = ('%%.%sf' % f.decimal_places) % field_val
+ else:
+ result_repr = EMPTY_CHANGELIST_VALUE
+ # Fields with choices are special: Use the representation
+ # of the choice.
+ elif f.choices:
+ result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
+ else:
+ result_repr = strip_tags(str(field_val))
+ if result_repr == '':
+ result_repr = '&nbsp;'
+ if first: # First column is a special case
+ first = False
+ url = cl.url_for_result(result)
+ result_id = getattr(result, pk)
+ yield ('<th%s><a href="%s"%s>%s</a></th>' % \
+ (row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr))
+ else:
+ yield ('<td%s>%s</td>' % (row_class, result_repr))
+
+def results(cl):
+ for res in cl.result_list:
+ yield list(items_for_result(cl,res))
+
+#@inclusion_tag("admin/change_list_results")
+def result_list(cl):
+ res = list(results(cl))
+ return {'cl': cl,
+ 'result_headers': list(result_headers(cl)),
+ 'results': list(results(cl))}
+result_list = inclusion_tag("admin/change_list_results")(result_list)
+
+#@inclusion_tag("admin/date_hierarchy")
+def date_hierarchy(cl):
+ lookup_opts, params, lookup_params, lookup_mod = \
+ cl.lookup_opts, cl.params, cl.lookup_params, cl.lookup_mod
+
+ if lookup_opts.admin.date_hierarchy:
+ field_name = 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)
+
+ def link(d):
+ return cl.get_query_string(d, [field_generic])
+
+ def get_dates(unit, params):
+ return getattr(lookup_mod, 'get_%s_list' % field_name)(unit, **params)
+
+ if year_lookup and month_lookup and day_lookup:
+ month_name = MONTHS[int(month_lookup)]
+ return {
+ 'show': True,
+ 'back': {
+ 'link': link({year_field: year_lookup, month_field: month_lookup}),
+ 'title': "%s %s" % (month_name, year_lookup)
+ },
+ '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)
+ return {
+ 'show': True,
+ 'back': {
+ 'link': link({year_field: year_lookup}),
+ 'title': year_lookup
+ },
+ 'choices': [{
+ 'link': link({year_field: year_lookup, month_field: month_lookup, day_field: day.day}),
+ 'title': day.strftime('%B %d')
+ } 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)
+ return {
+ 'show' : True,
+ 'back': {
+ 'link' : link({}),
+ 'title': _('All dates')
+ },
+ 'choices': [{
+ '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)
+ return {
+ 'show': True,
+ 'choices': [{
+ 'link': link({year_field: year.year}),
+ 'title': year.year
+ } for year in years ]
+ }
+date_hierarchy = inclusion_tag('admin/date_hierarchy')(date_hierarchy)
+
+#@inclusion_tag('admin/search_form')
+def search_form(cl):
+ return {
+ 'cl': cl,
+ 'show_result_count': cl.result_count != cl.full_result_count and not cl.opts.one_to_one_field,
+ 'search_var': SEARCH_VAR
+ }
+search_form = inclusion_tag('admin/search_form')(search_form)
+
+#@inclusion_tag('admin/filter')
+def filter(cl, spec):
+ return {'title': spec.title(), 'choices' : list(spec.choices(cl))}
+filter = inclusion_tag('admin/filter')(filter)
+
+#@inclusion_tag('admin/filters')
+def filters(cl):
+ return {'cl': cl}
+filters = inclusion_tag('admin/filters')(filters)
View
258 django/contrib/admin/templatetags/admin_modify.py
@@ -0,0 +1,258 @@
+from django.core import template, template_loader, meta
+from django.utils.html import escape
+from django.utils.text import capfirst
+from django.utils.functional import curry
+from django.core.template.decorators import simple_tag, inclusion_tag
+from django.contrib.admin.views.main import AdminBoundField
+from django.core.meta.fields import BoundField, Field
+from django.core.meta import BoundRelatedObject, TABULAR, STACKED
+from django.conf.settings import ADMIN_MEDIA_PREFIX
+import re
+
+word_re = re.compile('[A-Z][a-z]+')
+
+def class_name_to_underscored(name):
+ return '_'.join([s.lower() for s in word_re.findall(name)[:-1]])
+
+#@simple_tag
+def include_admin_script(script_path):
+ return '<script type="text/javascript" src="%s%s"></script>' % (ADMIN_MEDIA_PREFIX, script_path)
+include_admin_script = simple_tag(include_admin_script)
+
+#@inclusion_tag('admin/submit_line', takes_context=True)
+def submit_row(context, bound_manipulator):
+ change = context['change']
+ add = context['add']
+ show_delete = context['show_delete']
+ has_delete_permission = context['has_delete_permission']
+ is_popup = context['is_popup']
+ return {
+ 'onclick_attrib': (bound_manipulator.ordered_objects and change
+ and 'onclick="submitOrderForm();"' or ''),
+ 'show_delete_link': (not is_popup and has_delete_permission
+ and (change or show_delete)),
+ 'show_save_as_new': not is_popup and change and bound_manipulator.save_as,
+ 'show_save_and_add_another': not is_popup and (not bound_manipulator.save_as or add),
+ 'show_save_and_continue': not is_popup,
+ 'show_save': True
+ }
+submit_row = inclusion_tag('admin/submit_line', takes_context=True)(submit_row)
+
+#@simple_tag
+def field_label(bound_field):
+ class_names = []
+ if isinstance(bound_field.field, meta.BooleanField):
+ class_names.append("vCheckboxLabel")
+ colon = ""
+ else:
+ if not bound_field.field.blank:
+ class_names.append('required')
+ if not bound_field.first:
+ class_names.append('inline')
+ colon = ":"
+ class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
+ return '<label for="%s"%s>%s%s</label> ' % (bound_field.element_id, class_str, \
+ capfirst(bound_field.field.verbose_name), colon)
+field_label = simple_tag(field_label)
+
+class FieldWidgetNode(template.Node):
+ nodelists = {}
+ default = None
+
+ def __init__(self, bound_field_var):
+ self.bound_field_var = bound_field_var
+
+ def get_nodelist(cls, klass):
+ if not cls.nodelists.has_key(klass):
+ try:
+ field_class_name = klass.__name__
+ template_name = "widget/%s" % \
+ class_name_to_underscored(field_class_name)
+ nodelist = template_loader.get_template(template_name).nodelist
+ except template.TemplateDoesNotExist:
+ super_klass = bool(klass.__bases__) and klass.__bases__[0] or None
+ if super_klass and super_klass != Field:
+ nodelist = cls.get_nodelist(super_klass)
+ else:
+ if not cls.default:
+ cls.default = template_loader.get_template("widget/default").nodelist
+ nodelist = cls.default
+
+ cls.nodelists[klass] = nodelist
+ return nodelist
+ else:
+ return cls.nodelists[klass]
+ get_nodelist = classmethod(get_nodelist)
+
+ def render(self, context):
+ bound_field = template.resolve_variable(self.bound_field_var, context)
+
+ context.push()
+ context['bound_field'] = bound_field
+
+ output = self.get_nodelist(bound_field.field.__class__).render(context)
+ context.pop()
+ return output
+
+class FieldWrapper(object):
+ def __init__(self, field ):
+ self.field = field
+
+ def needs_header(self):
+ return not isinstance(self.field, meta.AutoField)
+
+ def header_class_attribute(self):
+ return self.field.blank and ' class="optional"' or ''
+
+ def use_raw_id_admin(self):
+ return isinstance(self.field.rel, (meta.ManyToOne, meta.ManyToMany)) \
+ and self.field.rel.raw_id_admin
+
+class FormFieldCollectionWrapper(object):
+ def __init__(self, field_mapping, fields):
+ self.field_mapping = field_mapping
+ self.fields = fields
+ self.bound_fields = [AdminBoundField(field, self.field_mapping, field_mapping['original'])
+ for field in self.fields]
+
+class TabularBoundRelatedObject(BoundRelatedObject):
+ def __init__(self, related_object, field_mapping, original):
+ super(TabularBoundRelatedObject, self).__init__(related_object, field_mapping, original)
+ self.field_wrapper_list = [FieldWrapper(field) for field in self.relation.editable_fields()]
+
+ fields = self.relation.editable_fields()
+
+ self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping, fields)
+ for field_mapping in self.field_mappings]
+ self.original_row_needed = max([fw.use_raw_id_admin() for fw in self.field_wrapper_list])
+ self.show_url = original and hasattr(self.relation.opts, 'get_absolute_url')
+
+ def template_name(self):
+ return "admin/edit_inline_tabular"
+
+class StackedBoundRelatedObject(BoundRelatedObject):
+ def __init__(self, related_object, field_mapping, original):
+ super(StackedBoundRelatedObject, self).__init__(related_object, field_mapping, original)
+ fields = self.relation.editable_fields()
+ self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping ,fields)
+ for field_mapping in self.field_mappings]
+ self.show_url = original and hasattr(self.relation.opts, 'get_absolute_url')
+
+ def template_name(self):
+ return "admin/edit_inline_stacked"
+
+bound_related_object_overrides = {
+ TABULAR: TabularBoundRelatedObject,
+ STACKED: StackedBoundRelatedObject,
+}
+
+class EditInlineNode(template.Node):
+ def __init__(self, rel_var):
+ self.rel_var = rel_var
+
+ def render(self, context):
+ relation = template.resolve_variable(self.rel_var, context)
+
+ context.push()
+
+ klass = relation.field.rel.edit_inline
+ bound_related_object_class = bound_related_object_overrides.get(klass, klass)
+
+ original = context.get('original', None)
+
+ bound_related_object = relation.bind(context['form'], original, bound_related_object_class)
+ context['bound_related_object'] = bound_related_object
+
+ t = template_loader.get_template(bound_related_object.template_name())
+
+ output = t.render(context)
+
+ context.pop()
+ return output
+
+#@simple_tag
+def output_all(form_fields):
+ return ''.join([str(f) for f in form_fields])
+output_all = simple_tag(output_all)
+
+#@simple_tag
+def auto_populated_field_script(auto_pop_fields, change = False):
+ for field in auto_pop_fields:
+ t = []
+ if change:
+ t.append('document.getElementById("id_%s")._changed = true;' % field.name)
+ else:
+ t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
+
+ add_values = ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
+ for f in field.prepopulate_from:
+ t.append('document.getElementById("id_%s").onkeyup = function() {' \
+ ' var e = document.getElementById("id_%s");' \
+ ' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % (
+ f, field.name, add_values, field.maxlength))
+ return ''.join(t)
+auto_populated_field_script = simple_tag(auto_populated_field_script)
+
+#@simple_tag
+def filter_interface_script_maybe(bound_field):
+ f = bound_field.field
+ if f.rel and isinstance(f.rel, meta.ManyToMany) and f.rel.filter_interface:
+ return '<script type="text/javascript">addEvent(window, "load", function(e) {' \
+ ' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % (
+ f.name, f.verbose_name, f.rel.filter_interface-1, ADMIN_MEDIA_PREFIX)
+ else:
+ return ''
+filter_interface_script_maybe = simple_tag(filter_interface_script_maybe)
+
+def do_one_arg_tag(node_factory, parser,token):
+ tokens = token.contents.split()
+ if len(tokens) != 2:
+ raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
+ return node_factory(tokens[1])
+
+def register_one_arg_tag(node):
+ tag_name = class_name_to_underscored(node.__name__)
+ parse_func = curry(do_one_arg_tag, node)
+ template.register_tag(tag_name, parse_func)
+
+one_arg_tag_nodes = (
+ FieldWidgetNode,
+ EditInlineNode,
+)
+
+for node in one_arg_tag_nodes:
+ register_one_arg_tag(node)
+
+#@inclusion_tag('admin/field_line', takes_context=True)
+def admin_field_line(context, argument_val):
+ if (isinstance(argument_val, BoundField)):
+ bound_fields = [argument_val]
+ else:
+ bound_fields = [bf for bf in argument_val]
+ add = context['add']
+ change = context['change']
+
+ class_names = ['form-row']
+ for bound_field in bound_fields:
+ for f in bound_field.form_fields:
+ if f.errors():
+ class_names.append('errors')
+ break
+
+ # Assumes BooleanFields won't be stacked next to each other!
+ if isinstance(bound_fields[0].field, meta.BooleanField):
+ class_names.append('checkbox-row')
+
+ return {
+ 'add': context['add'],
+ 'change': context['change'],
+ 'bound_fields': bound_fields,
+ 'class_names': " ".join(class_names),
+ }
+admin_field_line = inclusion_tag('admin/field_line', takes_context=True)(admin_field_line)
+
+#@simple_tag
+def object_pk(bound_manip, ordered_obj):
+ return bound_manip.get_ordered_object_pk(ordered_obj)
+
+object_pk = simple_tag(object_pk)
View
1,307 django/contrib/admin/views/main.py
@@ -1,19 +1,36 @@
-# Generic admin views, with admin templates created dynamically at runtime.
-
+# Generic admin views.
from django.contrib.admin.views.decorators import staff_member_required
-from django.core import formfields, meta
+from django.contrib.admin.filterspecs import FilterSpec
+from django.core import formfields, meta, template
from django.core.template import loader
+from django.core.meta.fields import BoundField, BoundFieldLine, BoundFieldSet
from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied
from django.core.extensions import DjangoContext as Context
from django.core.extensions import get_object_or_404, render_to_response
+from django.core.paginator import ObjectPaginator, InvalidPage
+from django.conf.settings import ADMIN_MEDIA_PREFIX
from django.models.admin import log
from django.utils.html import strip_tags
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
from django.utils.text import capfirst, get_text_list
-from django.conf.settings import ADMIN_MEDIA_PREFIX
-from django.utils.translation import get_date_formats
+from django.utils import dateformat
+from django.utils.dates import MONTHS
+from django.utils.html import escape
import operator
+# The system will display a "Show all" link only if the total result count
+# is less than or equal to this setting.
+MAX_SHOW_ALL_ALLOWED = 200
+
+DEFAULT_RESULTS_PER_PAGE = 100
+
+ALL_VAR = 'all'
+ORDER_VAR = 'o'
+ORDER_TYPE_VAR = 'ot'
+PAGE_VAR = 'p'
+SEARCH_VAR = 'q'
+IS_POPUP_VAR = 'pop'
+
# Text to display within changelist table cells if the value is blank.
EMPTY_CHANGELIST_VALUE = '(None)'
@@ -28,747 +45,354 @@ def _get_mod_opts(app_label, module_name):
raise Http404 # This object is valid but has no admin interface.
return mod, opts
-def get_query_string(original_params, new_params={}, remove=[]):
- """
- >>> get_query_string({'first_name': 'adrian', 'last_name': 'smith'})
- '?first_name=adrian&amp;last_name=smith'
- >>> get_query_string({'first_name': 'adrian', 'last_name': 'smith'}, {'first_name': 'john'})
- '?first_name=john&amp;last_name=smith'
- >>> get_query_string({'test': 'yes'}, {'blah': 'no'}, ['te'])
- '?blah=no'
- """
- p = original_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 p.has_key(k) and v is None:
- del p[k]
- elif v is not None:
- p[k] = v
- return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
-
def index(request):
- return render_to_response('admin/index', {'title': 'Site administration'}, context_instance=Context(request))
+ return render_to_response('admin/index', {'title': _('Site administration')}, context_instance=Context(request))
index = staff_member_required(index)
-def change_list(request, app_label, module_name):
- from django.core import paginator
- from django.utils import dateformat
- from django.utils.dates import MONTHS
- from django.utils.html import escape
- import datetime
-
- # The system will display a "Show all" link only if the total result count
- # is less than or equal to this setting.
- MAX_SHOW_ALL_ALLOWED = 200
-
- DEFAULT_RESULTS_PER_PAGE = 100
-
- ALL_VAR = 'all'
- ORDER_VAR = 'o'
- ORDER_TYPE_VAR = 'ot'
- PAGE_VAR = 'p'
- SEARCH_VAR = 'q'
- IS_POPUP_VAR = 'pop'
+class IncorrectLookupParameters(Exception):
+ pass
+
+class ChangeList(object):
+ def __init__(self, request, app_label, module_name):
+ self.get_modules_and_options(app_label, module_name, request)
+ self.get_search_parameters(request)
+ self.get_ordering()
+ self.query = request.GET.get(SEARCH_VAR,'')
+ self.get_lookup_params()
+ 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.pk_attname = self.lookup_opts.pk.attname
+
+ def get_filters(self, request):
+ self.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.has_output():
+ self.filter_specs.append(spec)
+ self.has_filters = bool(self.filter_specs)
+
+ def get_query_string(self, new_params={}, 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 p.has_key(k) and v is None:
+ del p[k]
+ elif v is not None:
+ p[k] = v
+ return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
- mod, opts = _get_mod_opts(app_label, module_name)
- if not request.user.has_perm(app_label + '.' + opts.get_change_permission()):
- raise PermissionDenied
+ def get_modules_and_options(self, app_label, module_name, request):
+ self.mod, self.opts = _get_mod_opts(app_label, module_name)
+ if not request.user.has_perm(app_label + '.' + self.opts.get_change_permission()):
+ raise PermissionDenied
- lookup_mod, lookup_opts = mod, opts
+ self.lookup_mod, self.lookup_opts = self.mod, self.opts
- # Get search parameters from the query string.
- try:
- page_num = int(request.GET.get(PAGE_VAR, 0))
- except ValueError:
- page_num = 0
- show_all = request.GET.has_key(ALL_VAR)
- is_popup = request.GET.has_key(IS_POPUP_VAR)
- params = dict(request.GET.copy())
- if params.has_key(PAGE_VAR):
- del params[PAGE_VAR]
- # 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 = lookup_opts.admin.ordering or lookup_opts.ordering or ['-' + lookup_opts.pk.name]
-
- # Normalize it to new-style ordering.
- ordering = meta.handle_legacy_orderlist(ordering)
-
- if ordering[0].startswith('-'):
- order_field, order_type = ordering[0][1:], 'desc'
- else:
- order_field, order_type = ordering[0], 'asc'
- if params.has_key(ORDER_VAR):
+ def get_search_parameters(self, request):
+ # Get search parameters from the query string.
try:
- try:
- f = lookup_opts.get_field(lookup_opts.admin.list_display[int(params[ORDER_VAR])])
- except meta.FieldDoesNotExist:
- pass
- else:
- if not isinstance(f.rel, meta.ManyToOne) or not f.null:
- order_field = f.name
- except (IndexError, ValueError):
- 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]
- query = request.GET.get(SEARCH_VAR, '')
-
- # Prepare the lookup parameters for the API lookup.
- lookup_params = params.copy()
- 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
- if isinstance(lookup_opts.get_field(order_field).rel, meta.ManyToOne):
- f = lookup_opts.get_field(order_field)
- rel_ordering = f.rel.to.ordering and f.rel.to.ordering[0] or f.rel.to.pk.column
- lookup_order_field = '%s.%s' % (f.rel.to.db_table, rel_ordering)
- if lookup_opts.admin.list_select_related:
- lookup_params['select_related'] = True
- else:
- # Use select_related if one of the list_display options is a field with
- # a relationship.
- for field_name in lookup_opts.admin.list_display:
- try:
- f = lookup_opts.get_field(field_name)
- except meta.FieldDoesNotExist:
- pass
- else:
- if isinstance(f.rel, meta.ManyToOne):
- lookup_params['select_related'] = True
- break
- lookup_params['order_by'] = ((order_type == 'desc' and '-' or '') + lookup_order_field,)
- if lookup_opts.admin.search_fields and query:
- or_queries = []
- for bit in query.split():
- or_query = []
- for field_name in lookup_opts.admin.search_fields:
- or_query.append(('%s__icontains' % field_name, bit))
- or_queries.append(or_query)
- lookup_params['_or'] = or_queries
-
- if opts.one_to_one_field:
- lookup_params.update(opts.one_to_one_field.rel.limit_choices_to)
-
- # Get the results.
- try:
- p = paginator.ObjectPaginator(lookup_mod, 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:
- return HttpResponseRedirect(request.path)
-
- # 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 = lookup_mod.get_count()
- else:
- full_result_count = p.hits
- del real_lookup_params
- result_count = p.hits
- 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 = lookup_mod.get_list(**lookup_params)
- else:
+ self.req_get = request.GET
+ 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.copy())
+ if self.params.has_key(PAGE_VAR):
+ del self.params[PAGE_VAR]
+
+ def get_results(self, request):
+ lookup_mod, lookup_params, show_all, page_num = \
+ self.lookup_mod, self.lookup_params, self.show_all, self.page_num
+ # Get the results.
try:
- result_list = p.get_page(page_num)
- except paginator.InvalidPage:
- result_list = []
-
- # Calculate filters first, because a CSS class high in the document depends
- # on whether they are available.
- filter_template = []
- if lookup_opts.admin.list_filter and not opts.one_to_one_field:
- filter_fields = [lookup_opts.get_field(field_name) for field_name in lookup_opts.admin.list_filter]
- for f in filter_fields:
- # Many-to-many or many-to-one filter.
- if f.rel:
- if isinstance(f, meta.ManyToManyField):
- lookup_title = f.rel.to.verbose_name
- else:
- lookup_title = f.verbose_name
- lookup_kwarg = '%s__%s__exact' % (f.name, f.rel.to.pk.name)
- lookup_val = request.GET.get(lookup_kwarg, None)
- lookup_choices = f.rel.to.get_model_module().get_list()
- if len(lookup_choices) > 1:
- filter_template.append('<h3>By %s:</h3>\n<ul>\n' % lookup_title)
- filter_template.append('<li%s><a href="%s">All</a></li>\n' % \
- ((lookup_val is None and ' class="selected"' or ''),
- get_query_string(params, {}, [lookup_kwarg])))
- for val in lookup_choices:
- pk_val = getattr(val, f.rel.to.pk.attname)
- filter_template.append('<li%s><a href="%s">%r</a></li>\n' % \
- ((lookup_val == str(pk_val) and ' class="selected"' or ''),
- get_query_string(params, {lookup_kwarg: pk_val}), val))
- filter_template.append('</ul>\n\n')
- # Field with choices.
- elif f.choices:
- lookup_kwarg = '%s__exact' % f.name
- lookup_val = request.GET.get(lookup_kwarg, None)
- filter_template.append('<h3>By %s:</h3><ul>\n' % f.verbose_name)
- filter_template.append('<li%s><a href="%s">All</a></li>\n' % \
- ((lookup_val is None and ' class="selected"' or ''),
- get_query_string(params, {}, [lookup_kwarg])))
- for k, v in f.choices:
- filter_template.append('<li%s><a href="%s">%s</a></li>' % \
- ((str(k) == lookup_val) and ' class="selected"' or '',
- get_query_string(params, {lookup_kwarg: k}), v))
- filter_template.append('</ul>\n\n')
- # Date filter.
- elif isinstance(f, meta.DateField):
- today = datetime.date.today()
- one_week_ago = today - datetime.timedelta(days=7)
- field_generic = '%s__' % f.name
- filter_template.append('<h3>By %s:</h3><ul>\n' % f.verbose_name)
- date_params = dict([(k, v) for k, v in params.items() if k.startswith(field_generic)])
- today_str = isinstance(f, meta.DateTimeField) and today.strftime('%Y-%m-%d 23:59:59') or today.strftime('%Y-%m-%d')
- for title, param_dict in (
- ('Any date', {}),
- ('Today', {'%s__year' % f.name: str(today.year), '%s__month' % f.name: str(today.month), '%s__day' % f.name: str(today.day)}),
- ('Past 7 days', {'%s__gte' % f.name: one_week_ago.strftime('%Y-%m-%d'), '%s__lte' % f.name: today_str}),
- ('This month', {'%s__year' % f.name: str(today.year), '%s__month' % f.name: str(today.month)}),
- ('This year', {'%s__year' % f.name: str(today.year)})
- ):
- filter_template.append('<li%s><a href="%s">%s</a></li>\n' % \
- ((date_params == param_dict) and ' class="selected"' or '',
- get_query_string(params, param_dict, field_generic), title))
- filter_template.append('</ul>\n\n')
- elif isinstance(f, meta.BooleanField) or isinstance(f, meta.NullBooleanField):
- lookup_kwarg = '%s__exact' % f.name
- lookup_kwarg2 = '%s__isnull' % f.name
- lookup_val = request.GET.get(lookup_kwarg, None)
- lookup_val2 = request.GET.get(lookup_kwarg2, None)
- filter_template.append('<h3>By %s:</h3><ul>\n' % f.verbose_name)
- for k, v in (('All', None), ('Yes', '1'), ('No', '0')):
- filter_template.append('<li%s><a href="%s">%s</a></li>\n' % \
- (((lookup_val == v and not lookup_val2) and ' class="selected"' or ''),
- get_query_string(params, {lookup_kwarg: v}, [lookup_kwarg2]), k))
- if isinstance(f, meta.NullBooleanField):
- filter_template.append('<li%s><a href="%s">%s</a></li>\n' % \
- (((lookup_val2 == 'True') and ' class="selected"' or ''),
- get_query_string(params, {lookup_kwarg2: 'True'}, [lookup_kwarg]), 'Unknown'))
- filter_template.append('</ul>\n\n')
- else:
- pass # Invalid argument to "list_filter"
-
- raw_template = ['{% extends "admin/base_site" %}\n']
- raw_template.append('{% block bodyclass %}change-list{% endblock %}\n')
- if not is_popup:
- raw_template.append('{%% block breadcrumbs %%}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; %s</div>{%% endblock %%}\n' % capfirst(opts.verbose_name_plural))
- raw_template.append('{% block coltype %}flex{% endblock %}')
- raw_template.append('{% block content %}\n')
- raw_template.append('<div id="content-main">\n')
- if request.user.has_perm(app_label + '.' + lookup_opts.get_add_permission()):
- raw_template.append('<ul class="object-tools"><li><a href="add/%s" class="addlink">Add %s</a></li></ul>\n' % ((is_popup and '?_popup=1' or ''), opts.verbose_name))
- raw_template.append('<div class="module%s" id="changelist">\n' % (filter_template and ' filtered' or ''))
-
- # Search form.
- if lookup_opts.admin.search_fields:
- raw_template.append('<div id="toolbar">\n<form id="changelist-search" action="" method="get">\n')
- raw_template.append('<label><img src="%simg/admin/icon_searchbox.png" /></label> ' % ADMIN_MEDIA_PREFIX)
- raw_template.append('<input type="text" size="40" name="%s" value="%s" id="searchbar" /> ' % \
- (SEARCH_VAR, escape(query)))
- raw_template.append('<input type="submit" value="Go" /> ')
- if result_count != full_result_count and not opts.one_to_one_field:
- raw_template.append('<span class="small quiet">%s result%s (<a href="?">%s total</a>)</span>' % \
- (result_count, (result_count != 1 and 's' or ''), full_result_count))
- for k, v in params.items():
- if k != SEARCH_VAR:
- raw_template.append('<input type="hidden" name="%s" value="%s" />' % (escape(k), escape(v)))
- raw_template.append('</form></div>\n')
- raw_template.append('<script type="text/javascript">document.getElementById("searchbar").focus();</script>')
-
- # Date-based navigation.
- if lookup_opts.admin.date_hierarchy:
- field_name = 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)
-
- raw_template.append('<div class="xfull">\n<ul class="toplinks">\n')
- if year_lookup and month_lookup and day_lookup:
- raw_template.append('<li class="date-back"><a href="%s">&lsaquo; %s %s </a></li>' % \
- (get_query_string(params, {year_field: year_lookup, month_field: month_lookup}, [field_generic]), MONTHS[int(month_lookup)], year_lookup))
- raw_template.append('<li>%s %s</li>' % (MONTHS[int(month_lookup)], day_lookup))
- elif year_lookup and month_lookup:
- raw_template.append('<li class="date-back"><a href="%s">&lsaquo; %s</a></li>' % \
- (get_query_string(params, {year_field: year_lookup}, [field_generic]), year_lookup))
- date_lookup_params = lookup_params.copy()
- date_lookup_params.update({year_field: year_lookup, month_field: month_lookup})
- for day in getattr(lookup_mod, 'get_%s_list' % field_name)('day', **date_lookup_params):
- raw_template.append('<li><a href="%s">%s</a></li>' % \
- (get_query_string(params, {year_field: year_lookup, month_field: month_lookup, day_field: day.day}, [field_generic]), day.strftime('%B %d')))
- elif year_lookup:
- raw_template.append('<li class="date-back"><a href="%s">&lsaquo; All dates</a></li>' % \
- get_query_string(params, {}, [year_field]))
- date_lookup_params = lookup_params.copy()
- date_lookup_params.update({year_field: year_lookup})
- for month in getattr(lookup_mod, 'get_%s_list' % field_name)('month', **date_lookup_params):
- raw_template.append('<li><a href="%s">%s %s</a></li>' % \
- (get_query_string(params, {year_field: year_lookup, month_field: month.month}, [field_generic]), month.strftime('%B'), month.year))
+ paginator = ObjectPaginator(lookup_mod, 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:
+ 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 = lookup_mod.get_count()
+ else:
+ full_result_count = paginator.hits
+ del real_lookup_params
+ result_count = paginator.hits
+ 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 = lookup_mod.get_list(**lookup_params)
else:
- for year in getattr(lookup_mod, 'get_%s_list' % field_name)('year', **lookup_params):
- raw_template.append('<li><a href="%s">%s</a></li>\n' % \
- (get_query_string(params, {year_field: year.year}, [field_generic]), year.year))
- raw_template.append('</ul><br class="clear" />\n</div>\n')
-
- # Filters.
- if filter_template:
- raw_template.append('<div id="changelist-filter">\n<h2>Filter</h2>\n')
- raw_template.extend(filter_template)
- raw_template.append('</div>')
- del filter_template
-
- # Result table.
- if result_list:
- # Table headers.
- raw_template.append('<table cellspacing="0">\n<thead>\n<tr>\n')
- for i, field_name in enumerate(lookup_opts.admin.list_display):
try:
- f = lookup_opts.get_field(field_name)
- except meta.FieldDoesNotExist:
- # For non-field list_display values, check for the function
- # attribute "short_description". If that doesn't exist, fall
- # back to the method name. And __repr__ is a special-case.
- if field_name == '__repr__':
- header = lookup_opts.verbose_name
- else:
- func = getattr(mod.Klass, field_name) # Let AttributeErrors propogate.
- try:
- header = func.short_description
- except AttributeError:
- header = func.__name__.replace('_', ' ')
- # Non-field list_display values don't get ordering capability.
- raw_template.append('<th>%s</th>' % capfirst(header))
- else:
- if isinstance(f.rel, meta.ManyToOne) and f.null:
- raw_template.append('<th>%s</th>' % capfirst(f.verbose_name))
+ result_list = paginator.get_page(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 )
+
+ def url_for_result(self, result):
+ return "%s/" % getattr(result, self.pk_attname)
+
+ 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 = lookup_opts.admin.ordering or lookup_opts.ordering or ['-' + lookup_opts.pk.name]
+
+ # Normalize it to new-style ordering.
+ ordering = meta.handle_legacy_orderlist(ordering)
+
+ if ordering[0].startswith('-'):
+ order_field, order_type = ordering[0][1:], 'desc'
+ else:
+ order_field, order_type = ordering[0], 'asc'
+ if params.has_key(ORDER_VAR):
+ try:
+ try:
+ f = lookup_opts.get_field(lookup_opts.admin.list_display[int(params[ORDER_VAR])])
+ except meta.FieldDoesNotExist:
+ pass
else:
- th_classes = []
- new_order_type = 'asc'
- if field_name == order_field:
- th_classes.append('sorted %sending' % order_type.lower())
- new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type.lower()]
- raw_template.append('<th%s><a href="%s">%s</a></th>' % \
- ((th_classes and ' class="%s"' % ' '.join(th_classes) or ''),
- get_query_string(params, {ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
- capfirst(f.verbose_name)))
- raw_template.append('</tr>\n</thead>\n')
- # Result rows.
- pk = lookup_opts.pk.attname
- for i, result in enumerate(result_list):
- raw_template.append('<tr class="row%s">\n' % (i % 2 + 1))
- for j, field_name in enumerate(lookup_opts.admin.list_display):
- row_class = ''
+ if not isinstance(f.rel, meta.ManyToOne) or not f.null:
+ order_field = f.name
+ except (IndexError, ValueError):
+ 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
+
+ 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()
+ 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 meta.FieldDoesNotExist:
+ pass
+ else:
+ if isinstance(lookup_opts.get_field(order_field).rel, meta.ManyToOne):
+ f = lookup_opts.get_field(order_field)
+ rel_ordering = f.rel.to.ordering and f.rel.to.ordering[0] or f.rel.to.pk.column
+ lookup_order_field = '%s.%s' % (f.rel.to.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:
try:
f = lookup_opts.get_field(field_name)
except meta.FieldDoesNotExist:
- # For non-field list_display values, the value is a method
- # name. Execute the method.
- func = getattr(result, field_name)
- try:
- result_repr = str(func())
- except ObjectDoesNotExist:
- result_repr = EMPTY_CHANGELIST_VALUE
- else:
- # Strip HTML tags in the resulting text, except if the
- # function has an "allow_tags" attribute set to True.
- if not getattr(func, 'allow_tags', False):
- result_repr = strip_tags(result_repr)
+ pass
else:
- field_val = getattr(result, f.attname)
- # Foreign-key fields are special: Use the repr of the
- # related object.
if isinstance(f.rel, meta.ManyToOne):
- if field_val is not None:
- result_repr = getattr(result, 'get_%s' % f.name)()
- else:
- result_repr = EMPTY_CHANGELIST_VALUE
- # Dates and times are special: They're formatted in a certain way.
- elif isinstance(f, meta.DateField) or isinstance(f, meta.TimeField):
- if field_val:
- (date_format, datetime_format, time_format) = get_date_formats()
- if isinstance(f, meta.DateTimeField):
- result_repr = capfirst(dateformat.format(field_val, datetime_format))
- elif isinstance(f, meta.TimeField):
- result_repr = capfirst(dateformat.time_format(field_val, time_format))
- else:
- result_repr = capfirst(dateformat.format(field_val, date_format))
- else:
- result_repr = EMPTY_CHANGELIST_VALUE
- row_class = ' class="nowrap"'
- # Booleans are special: We use images.
- elif isinstance(f, meta.BooleanField) or isinstance(f, meta.NullBooleanField):
- BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
- result_repr = '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
- # ImageFields are special: Use a thumbnail.
- elif isinstance(f, meta.ImageField):
- from django.parts.media.photos import get_thumbnail_url
- result_repr = '<img src="%s" alt="%s" title="%s" />' % (get_thumbnail_url(getattr(result, 'get_%s_url' % f.name)(), '120'), field_val, field_val)
- # FloatFields are special: Zero-pad the decimals.
- elif isinstance(f, meta.FloatField):
- if field_val is not None:
- result_repr = ('%%.%sf' % f.decimal_places) % field_val
- else:
- result_repr = EMPTY_CHANGELIST_VALUE
- # Fields with choices are special: Use the representation
- # of the choice.
- elif f.choices:
- result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
- else:
- result_repr = strip_tags(str(field_val))
- # Some browsers don't like empty "<td></td>"s.
- if result_repr == '':
- result_repr = '&nbsp;'
- if j == 0: # First column is a special case
- result_id = getattr(result, pk)
- raw_template.append('<th%s><a href="%s/"%s>%s</a></th>' % \
- (row_class, result_id, (is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr))
- else:
- raw_template.append('<td%s>%s</td>' % (row_class, result_repr))
- raw_template.append('</tr>\n')
- del result_list # to free memory
- raw_template.append('</table>\n')
- else:
- raw_template.append('<p>No %s matched your search criteria.</p>' % opts.verbose_name_plural)
+ lookup_params['select_related'] = True
+ break
+ lookup_params['order_by'] = ((order_type == 'desc' and '-' or '') + lookup_order_field,)
+ if lookup_opts.admin.search_fields and query:
+ or_queries = []
+ for bit in query.split():
+ or_query = []
+ for field_name in lookup_opts.admin.search_fields:
+ or_query.append(('%s__icontains' % field_name, bit))
+ or_queries.append(or_query)
+ lookup_params['_or'] = or_queries
+
+ if opts.one_to_one_field:
+ lookup_params.update(opts.one_to_one_field.rel.limit_choices_to)
+ self.lookup_params = lookup_params
+
+
+def change_list(request, app_label, module_name):
+ try:
+ cl = ChangeList(request, app_label, module_name)
+ except IncorrectLookupParameters:
+ return HttpResponseRedirect(request.path)
- # Pagination.
- raw_template.append('<p class="paginator">')
- if (show_all and can_show_all) or not multi_page:
- pass
- else:
- raw_template.append('Page &rsaquo; ')
- ON_EACH_SIDE = 3
- ON_ENDS = 2
- DOT = '.'
- # If there are 10 or fewer pages, display links to every page.
- # Otherwise, do some fancy
- if p.pages <= 10:
- page_range = range(p.pages)
- else:
- # Insert "smart" pagination links, so that there are always ON_ENDS
- # links at either end of the list of pages, and there are always
- # ON_EACH_SIDE links at either end of the "current page" link.
- page_range = []
- if page_num > (ON_EACH_SIDE + ON_ENDS):
- page_range.extend(range(0, ON_EACH_SIDE - 1))
- page_range.append(DOT)
- page_range.extend(range(page_num - ON_EACH_SIDE, page_num + 1))
- else:
- page_range.extend(range(0, page_num + 1))
- if page_num < (p.pages - ON_EACH_SIDE - ON_ENDS - 1):
- page_range.extend(range(page_num + 1, page_num + ON_EACH_SIDE + 1))
- page_range.append(DOT)
- page_range.extend(range(p.pages - ON_ENDS, p.pages))
- else:
- page_range.extend(range(page_num + 1, p.pages))
- for i in page_range:
- if i == DOT:
- raw_template.append('... ')
- elif i == page_num:
- raw_template.append('<span class="this-page">%d</span> ' % (i+1))
- else:
- raw_template.append('<a href="%s"%s>%d</a> ' % \
- (get_query_string(params, {PAGE_VAR: i}), (i == p.pages-1 and ' class="end"' or ''), i+1))
- raw_template.append('%s %s' % (result_count, result_count == 1 and opts.verbose_name or opts.verbose_name_plural))
- if can_show_all and not show_all and multi_page:
- raw_template.append('&nbsp;&nbsp;<a href="%s" class="showall">Show all</a>' % \
- get_query_string(params, {ALL_VAR: ''}))
- raw_template.append('</p>')
-
- raw_template.append('</div>\n</div>')
- raw_template.append('{% endblock %}\n')
- t = loader.get_template_from_string(''.join(raw_template))
c = Context(request, {
- 'title': (is_popup and 'Select %s' % opts.verbose_name or 'Select %s to change' % opts.verbose_name),
- 'is_popup': is_popup,
+ 'title': cl.title,
+ 'is_popup': cl.is_popup,
+ 'cl' : cl
})
- return HttpResponse(t.render(c))
+ c.update( { 'has_add_permission': c['perms'][app_label][cl.opts.get_add_permission()]}),
+ return render_to_response('admin/change_list',
+ context_instance = c)
change_list = staff_member_required(change_list)
-def _get_flattened_data(field, val):
- """
- Returns a dictionary mapping the field's manipulator field names to its
- "flattened" string values for the admin view. "val" is an instance of the
- field's value.
- """
- if isinstance(field, meta.DateTimeField):
- date_field, time_field = field.get_manipulator_field_names('')
- return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''),
- time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
- elif isinstance(field, meta.DateField):
- return {field.name: (val is not None and val.strftime("%Y-%m-%d") or '')}
- elif isinstance(field, meta.TimeField):
- return {field.name: (val is not None and val.strftime("%H:%M:%S") or '')}
- else:
- return {field.name: val}
use_raw_id_admin = lambda field: isinstance(field.rel, (meta.ManyToOne, meta.ManyToMany)) and field.rel.raw_id_admin
-def _get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects):
- t = ['<div class="submit-row">']
- if change or show_delete:
- t.append('{%% if perms.%s.%s %%}{%% if not is_popup %%}<p class="float-left"><a href="delete/" class="deletelink">Delete</a></p>{%% endif %%}{%% endif %%}' % \
- (app_label, opts.get_delete_permission()))
- if change and opts.admin.save_as:
- t.append('{%% if not is_popup %%}<input type="submit" value="Save as new" name="_saveasnew" %s/>{%% endif %%}' % \
- (ordered_objects and change and 'onclick="submitOrderForm();"' or ''))
- if not opts.admin.save_as or add:
- t.append('{%% if not is_popup %%}<input type="submit" value="Save and add another" name="_addanother" %s/>{%% endif %%}' % \
- (ordered_objects and change and 'onclick="submitOrderForm();"' or ''))
- t.append('{%% if not is_popup %%}<input type="submit" value="Save and continue editing" name="_continue" %s/>{%% endif %%}' % \
- (ordered_objects and change and 'onclick="submitOrderForm();"' or ''))
- t.append('<input type="submit" value="Save" class="default" %s/>' % \
- (ordered_objects and change and 'onclick="submitOrderForm();"' or ''))
- t.append('</div>\n')
- return t
-
-def _get_template(opts, app_label, add=False, change=False, show_delete=False, form_url=''):
- admin_field_objs = opts.admin.get_field_objs(opts)
- ordered_objects = opts.get_ordered_objects()[:]
- auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
- t = ['{% extends "admin/base_site" %}\n']
- t.append('{% block extrahead %}')
-
- # Put in any necessary JavaScript imports.
- javascript_imports = ['%sjs/core.js' % ADMIN_MEDIA_PREFIX, '%sjs/admin/RelatedObjectLookups.js' % ADMIN_MEDIA_PREFIX]
+
+def get_javascript_imports(opts,auto_populated_fields, ordered_objects, field_sets):
+# Put in any necessary JavaScript imports.
+ js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
if auto_populated_fields:
- javascript_imports.append('%sjs/urlify.js' % ADMIN_MEDIA_PREFIX)
+ js.append('js/urlify.js')
if opts.has_field_type(meta.DateTimeField) or opts.has_field_type(meta.TimeField) or opts.has_field_type(meta.DateField):
- javascript_imports.extend(['%sjs/calendar.js' % ADMIN_MEDIA_PREFIX, '%sjs/admin/DateTimeShortcuts.js' % ADMIN_MEDIA_PREFIX])
+ js.extend(['js/calendar.js', 'js/admin/DateTimeShortcuts.js'])
if ordered_objects:
- javascript_imports.extend(['%sjs/getElementsBySelector.js' % ADMIN_MEDIA_PREFIX, '%sjs/dom-drag.js' % ADMIN_MEDIA_PREFIX, '%sjs/admin/ordering.js' % ADMIN_MEDIA_PREFIX])
+ js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
if opts.admin.js:
- javascript_imports.extend(opts.admin.js)
+ js.extend(opts.admin.js)
seen_collapse = False
- for _, options in admin_field_objs:
- if not seen_collapse and 'collapse' in options.get('classes', ''):
+ for field_set in field_sets:
+ if not seen_collapse and 'collapse' in field_set.classes:
seen_collapse = True
- javascript_imports.append('%sjs/admin/CollapsedFieldsets.js' % ADMIN_MEDIA_PREFIX)
- for field_list in options['fields']:
+ js.append('js/admin/CollapsedFieldsets.js' )
+
+ for field_line in field_set:
try:
- for f in field_list:
+ for f in field_line:
if f.rel and isinstance(f, meta.ManyToManyField) and f.rel.filter_interface:
- javascript_imports.extend(['%sjs/SelectBox.js' % ADMIN_MEDIA_PREFIX, '%sjs/SelectFilter2.js' % ADMIN_MEDIA_PREFIX])
+ js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
raise StopIteration
except StopIteration:
break
- for j in javascript_imports:
- t.append('<script type="text/javascript" src="%s"></script>' % j)
-
- t.append('{% endblock %}\n')
- if ordered_objects:
- coltype = 'colMS'
- else:
- coltype = 'colM'
- t.append('{%% block coltype %%}%s{%% endblock %%}\n' % coltype)
- t.append('{%% block bodyclass %%}%s-%s change-form{%% endblock %%}\n' % (app_label, opts.object_name.lower()))
- breadcrumb_title = add and "Add %s" % opts.verbose_name or '{{ original|striptags|truncatewords:"18" }}'
- t.append('{%% block breadcrumbs %%}{%% if not is_popup %%}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../">%s</a> &rsaquo; %s</div>{%% endif %%}{%% endblock %%}\n' % \
- (capfirst(opts.verbose_name_plural), breadcrumb_title))
- t.append('{% block content %}<div id="content-main">\n')
- if change:
- t.append('{% if not is_popup %}')
- t.append('<ul class="object-tools"><li><a href="history/" class="historylink">History</a></li>')
- if hasattr(opts.get_model_module().Klass, 'get_absolute_url'):
- t.append('<li><a href="/r/%s/{{ object_id }}/" class="viewsitelink">View on site</a></li>' % opts.get_content_type_id())
- t.append('</ul>\n')
- t.append('{% endif %}')
- t.append('<form ')
- if opts.has_field_type(meta.FileField):
- t.append('enctype="multipart/form-data" ')
- t.append('action="%s" method="post">\n' % form_url)
- t.append('{% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}')
- if opts.admin.save_on_top:
- t.extend(_get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects))
- t.append('{% if form.error_dict %}<p class="errornote">Please correct the error{{ form.error_dict.items|pluralize }} below.</p>{% endif %}\n')
- for fieldset_name, options in admin_field_objs:
- t.append('<fieldset class="module aligned %s">\n\n' % options.get('classes', ''))
- if fieldset_name:
- t.append('<h2>%s</h2>\n' % fieldset_name)
- for field_list in options['fields']:
- t.append(_get_admin_field(field_list, 'form.', False, add, change))
- for f in field_list:
- if f.rel and isinstance(f, meta.ManyToManyField) and f.rel.filter_interface:
- t.append('<script type="text/javascript">addEvent(window, "load", function(e) { SelectFilter.init("id_%s", "%s", %s, %r); });</script>\n' % (f.name, f.verbose_name, f.rel.filter_interface-1, ADMIN_MEDIA_PREFIX))
- t.append('</fieldset>\n')
- if ordered_objects and change:
- t.append('<fieldset class="module"><h2>Ordering</h2>')
- t.append('<div class="form-row{% if form.order_.errors %} error{% endif %} ">\n')
- t.append('{% if form.order_.errors %}{{ form.order_.html_error_list }}{% endif %}')
- t.append('<p><label for="id_order_">Order:</label> {{ form.order_ }}</p>\n')
- t.append('</div></fieldset>\n')
- for rel_obj, rel_field in opts.get_inline_related_objects():
- var_name = rel_obj.object_name.lower()
- field_list = [f for f in rel_obj.fields + rel_obj.many_to_many if f.editable and f != rel_field]
- t.append('<fieldset class="module%s">\n' % ((rel_field.rel.edit_inline != meta.TABULAR) and ' aligned' or ''))
- view_on_site = ''
- if change and hasattr(rel_obj, 'get_absolute_url'):
- view_on_site = '{%% if %s.original %%}<a href="/r/{{ %s.content_type_id }}/{{ %s.original.id }}/">View on site</a>{%% endif %%}' % (var_name, var_name, var_name)
- if rel_field.rel.edit_inline == meta.TABULAR:
- t.append('<h2>%s</h2>\n<table>\n' % capfirst(rel_obj.verbose_name_plural))
- t.append('<thead><tr>')
- for f in field_list:
- if isinstance(f, meta.AutoField):
- continue
- t.append('<th%s>%s</th>' % (f.blank and ' class="optional"' or '', capfirst(f.verbose_name)))
- t.append('</tr></thead>\n')
- t.append('{%% for %s in form.%s %%}\n' % (var_name, rel_obj.module_name))
- if change:
- for f in field_list:
- if use_raw_id_admin(f):
- t.append('{%% if %s.original %%}' % var_name)
- t.append('<tr class="row-label {% cycle row1,row2 %}">')
- t.append('<td colspan="%s"><strong>{{ %s.original }}</strong></td>' % (30, var_name))
- t.append('</tr>{% endif %}\n')
- break
- t.append('{%% if %s %%}\n' % ' or '.join(['%s.%s.errors' % (var_name, f.name) for f in field_list]))
- t.append('<tr class="errorlist"><td colspan="%s">%s</td></tr>\n{%% endif %%}\n' % \
- (len(field_list), ''.join(['{{ %s.%s.html_error_list }}' % (var_name, f.name) for f in field_list])))
- t.append('<tr class="{% cycle row1,row2 %}">\n')
- hidden_fields = []
- for f in field_list:
- form_widget = _get_admin_field_form_widget(f, var_name+'.', True, add, change)
- # Don't put AutoFields within a <td>, because they're hidden.
- if not isinstance(f, meta.AutoField):
- # Fields with raw_id_admin=True get class="nowrap".
- if use_raw_id_admin(f):
- t.append('<td class="nowrap {%% if %s.%s.errors %%}error"{%% endif %%}">%s</td>\n' % (var_name, f.name, form_widget))
- else:
- t.append('<td{%% if %s.%s.errors %%} class="error"{%% endif %%}>%s</td>\n' % (var_name, f.name, form_widget))
- else:
- hidden_fields.append(form_widget)
- if hasattr(rel_obj, 'get_absolute_url'):
- t.append('<td>%s</td>\n' % view_on_site)
- t.append('</tr>\n')
- t.append('{% endfor %}\n</table>\n')
- # Write out the hidden fields. We didn't write them out earlier
- # because it would've been invalid HTML.
- t.append('{%% for %s in form.%s %%}\n' % (var_name, rel_obj.module_name))
- t.extend(hidden_fields)
- t.append('{% endfor %}\n')
- else: # edit_inline == STACKED
- t.append('{%% for %s in form.%s %%}' % (var_name, rel_obj.module_name))
- t.append('<h2>%s #{{ forloop.counter }}</h2>' % capfirst(rel_obj.verbose_name))
- if view_on_site:
- t.append('<p>%s</p>' % view_on_site)
- for f in field_list:
- # Don't put AutoFields within the widget -- just use the field.
- if isinstance(f, meta.AutoField):
- t.append(_get_admin_field_form_widget(f, var_name+'.', True, add, change))
- else:
- t.append(_get_admin_field([f], var_name+'.', True, add, change))
- t.append('{% endfor %}\n')
- t.append('</fieldset>\n')
- t.extend(_get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects))
- if add:
- # Add focus to the first field on the form, if this is an "add" form.
- t.append('<script type="text/javascript">document.getElementById("id_%s").focus();</script>' % \
- admin_field_objs[0][1]['fields'][0][0].get_manipulator_field_names('')[0])
- if auto_populated_fields:
- t.append('<script type="text/javascript">')
- for field in auto_populated_fields:
- if change:
- t.append('document.getElementById("id_%s")._changed = true;' % field.name)
- else:
- t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
- for f in field.prepopulate_from:
- t.append('document.getElementById("id_%s").onkeyup = function() { var e = document.getElementById("id_%s"); if (!e._changed) { e.value = URLify(%s, %s);}};' % \
- (f, field.name, ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from]), field.maxlength))
- t.append('</script>\n')
- if change and ordered_objects:
- t.append('{% if form.order_objects %}<ul id="orderthese">{% for object in form.order_objects %}')
- t.append('<li id="p{%% firstof %(x)s %%}"><span id="handlep{%% firstof %(x)s %%}">{{ object|truncatewords:"5" }}</span></li>' % \
- {'x': ' '.join(['object.%s' % o.pk.name for o in ordered_objects])})
- t.append('{% endfor %}</ul>{% endif %}\n')
- t.append('</form>\n</div>\n{% endblock %}')
- return ''.join(t)
-
-def _get_admin_field(field_list, name_prefix, rel, add, change):
- "Returns the template code for editing the given list of fields in the admin template."
- field_names = []
- for f in field_list:
- field_names.extend(f.get_manipulator_field_names(name_prefix))
- div_class_names = ['form-row', '{%% if %s %%} error{%% endif %%}' % ' or '.join(['%s.errors' % n for n in field_names])]
- # Assumes BooleanFields won't be stacked next to each other!
- if isinstance(field_list[0], meta.BooleanField):
- div_class_names.append('checkbox-row')
- t = []
- t.append('<div class="%s">\n' % ' '.join(div_class_names))
- for n in field_names:
- t.append('{%% if %s.errors %%}{{ %s.html_error_list }}{%% endif %%}\n' % (n, n))
- for i, field in enumerate(field_list):
- label_name = 'id_%s%s' % ((rel and "%s{{ forloop.counter0 }}." % name_prefix or ""), field.get_manipulator_field_names('')[0])
- # BooleanFields are a special case, because the checkbox widget appears to
- # the *left* of the label.
- if isinstance(field, meta.BooleanField):
- t.append(_get_admin_field_form_widget(field, name_prefix, rel, add, change))
- t.append(' <label for="%s" class="vCheckboxLabel">%s</label>' % (label_name, capfirst(field.verbose_name)))
- else:
- class_names = []
- if not field.blank:
- class_names.append('required')
- if i > 0:
- class_names.append('inline')
- t.append('<label for="%s"%s>%s:</label> ' % (label_name, class_names and ' class="%s"' % ' '.join(class_names) or '', capfirst(field.verbose_name)))
- t.append(_get_admin_field_form_widget(field, name_prefix, rel, add, change))
- if change and field.primary_key:
- t.append('{{ %soriginal.%s }}' % ((rel and name_prefix or ''), field.name))
- if change and use_raw_id_admin(field):
- if isinstance(field.rel, meta.ManyToOne):
- if_bit = '%soriginal.get_%s' % (rel and name_prefix or '', field.name)
- obj_repr = if_bit + '|truncatewords:"14"'
- elif isinstance(field.rel, meta.ManyToMany):
- if_bit = '%soriginal.get_%s_list' % (rel and name_prefix or '', field.name)
- obj_repr = if_bit + '|join:", "|truncatewords:"14"'
- t.append('{%% if %s %%}&nbsp;<strong>{{ %s }}</strong>{%% endif %%}' % (if_bit, obj_repr))
- if field.help_text:
- t.append('<p class="help">%s</p>\n' % field.help_text)
- t.append('</div>\n\n')
- return ''.join(t)
-
-def _get_admin_field_form_widget(field, name_prefix, rel, add, change):
- "Returns JUST the formfield widget for the field's admin interface."
- field_names = field.get_manipulator_field_names(name_prefix)
- if isinstance(field, meta.DateTimeField):
- return '<p class="datetime">Date: {{ %s }}<br />Time: {{ %s }}</p>' % tuple(field_names)
- t = ['{{ %s }}' % n for n in field_names]
- if change and isinstance(field, meta.FileField):
- return '{%% if %soriginal.%s %%}Currently: <a href="{{ %soriginal.get_%s_url }}">{{ %soriginal.%s }}</a><br />Change: %s{%% else %%}%s{%% endif %%}' % \
- (name_prefix, field.name, name_prefix, field.name, name_prefix, field.name, ''.join(t), ''.join(t))
- field_id = 'id_%s%s' % ((rel and "%s{{ forloop.counter0 }}." % name_prefix or ""), field.get_manipulator_field_names('')[0])
- # raw_id_admin fields get the little lookup link next to them
- if use_raw_id_admin(field):
- t.append(' <a href="../../../%s/%s/" class="related-lookup" id="lookup_%s" onclick="return showRelatedObjectLookupPopup(this);">' % \
- (field.rel.to.app_label, field.rel.to.module_name, field_id))
- t.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % ADMIN_MEDIA_PREFIX)
- # fields with relationships to editable objects get an "add another" link,
- # but only if the field doesn't have raw_admin ('cause in that case they get
- # the "add" button in the popup)
- elif field.rel and (isinstance(field.rel, meta.ManyToOne) or isinstance(field.rel, meta.ManyToMany)) and field.rel.to.admin:
- t.append('{%% if perms.%s.%s %%}' % (field.rel.to.app_label, field.rel.to.get_add_permission()))
- t.append(' <a href="../../../%s/%s/add/" class="add-another" id="add_%s" onclick="return showAddAnotherPopup(this);">' % \
- (field.rel.to.app_label, field.rel.to.module_name, field_id))
- t.append('<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="Add Another" /></a>' % ADMIN_MEDIA_PREFIX)
- t.append('{% endif %}')
- return ''.join(t)
+ return js
+
+
+class AdminBoundField(BoundField):
+ def __init__(self, field, field_mapping, original):
+ super(AdminBoundField, self).__init__(field,field_mapping,original)
+
+ self.element_id = self.form_fields[0].get_id()
+ self.has_label_first = not isinstance(self.field, meta.BooleanField)
+ self.raw_id_admin = use_raw_id_admin(field)
+ self.is_date_time = isinstance(field, meta.DateTimeField)
+ self.is_file_field = isinstance(field, meta.FileField)
+ self.needs_add_label = field.rel and isinstance(field.rel, meta.ManyToOne) or isinstance(field.rel, meta.ManyToMany) and field.rel.to.admin
+ self.hidden = isinstance(self.field, meta.AutoField)
+ self.first = False
+
+ classes = []
+ if(self.raw_id_admin):
+ classes.append('nowrap')
+ if max([bool(f.errors()) for f in self.form_fields]):
+ classes.append('error')
+ if classes:
+ self.cell_class_attribute = ' class="%s" ' % ' '.join(classes)
+ self._repr_filled = False
+
+ def _fetch_existing_display(self, func_name):
+ class_dict = self.original.__class__.__dict__
+ func = class_dict.get(func_name)
+