Commit 9dda4abe authored by Adrian Holovaty's avatar Adrian Holovaty
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
parent 4fe5c9b7
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -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, \
+152 −0
Original line number Diff line number Diff line
"""
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)
+75 −0
Original line number Diff line number Diff line
{% 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 %}
+20 −0
Original line number Diff line number Diff line
{% 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 %}
+13 −0
Original line number Diff line number Diff line
<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>
Loading