开发者

Display number of instances for each model in Django's admin index

I need to display number of objects at main django site admin page. For example, in list of models I need to display

Elephants (6) 

instead of

Elephants

I added this code to my model:

class Elephant(models.Model):
    ....
    class Meta:
        verbose_name_plural = 'Elephants ' + '(' + unicode(count_elephants()) + ')'

where count_elephants() calculates number of objects. The problem is that verbose_name_plural is calculated at server start and is not called when 开发者_开发技巧I delete/insert objects, so this calculated value becomes irrelevant. Is it possible to do it in correct way? Thanks!


Since verbose_name_plural is used in many other ways, a better way to do this will be to change the admin index view and admin template.

However, since the admin app can change, this is probably tied to a specific version of django. I am attaching for example the modified admin taken from django 1.2.5.

(Note: I will use an in place replacement for the index method, but it will be probably better to subclass it instead of replacing the method)

As a start, copy from django/contrib/admin/sites.py the AdminSite.index method and it's required imports, and modify it to include counts (one line changed, look for 'THIS LINE WAS ADDED"). Add it to any of your admin.py files or somewhere else appropriate:

from django.utils.text import capfirst
from django import template
from django.shortcuts import render_to_response
from django.views.decorators.cache import never_cache
from django.utils.translation import ugettext as _

def index_with_count(self, request, extra_context=None):
    """
    Displays the main admin index page, which lists all of the installed
    apps that have been registered in this site.
    """
    app_dict = {}
    user = request.user
    for model, model_admin in self._registry.items():
        app_label = model._meta.app_label
        has_module_perms = user.has_module_perms(app_label)

        if has_module_perms:
            perms = model_admin.get_model_perms(request)

            # Check whether user has any perm for this module.
            # If so, add the module to the model_list.
            if True in perms.values():
                model_dict = {
                    'name': capfirst(model._meta.verbose_name_plural),
                    'admin_url': mark_safe('%s/%s/' % (app_label, model.__name__.lower())),
                    'perms': perms,
                    'count': model.objects.count(), # THIS LINE WAS ADDED
                }
                if app_label in app_dict:
                    app_dict[app_label]['models'].append(model_dict)
                else:
                    app_dict[app_label] = {
                        'name': app_label.title(),
                        'app_url': app_label + '/',
                        'has_module_perms': has_module_perms,
                        'models': [model_dict],
                    }

    # Sort the apps alphabetically.
    app_list = app_dict.values()
    app_list.sort(lambda x, y: cmp(x['name'], y['name']))

    # Sort the models alphabetically within each app.
    for app in app_list:
        app['models'].sort(lambda x, y: cmp(x['name'], y['name']))

    context = {
        'title': _('Site administration'),
        'app_list': app_list,
        'root_path': self.root_path,
    }
    context.update(extra_context or {})
    context_instance = template.RequestContext(request, current_app=self.name)
    return render_to_response(self.index_template or 'admin/index.html', context,
        context_instance=context_instance
    )

site.index = never_cache(type(site.index)(index_with_count, site, AdminSite))

Now copy the django/contrib/admin/templates/admin/index.html file into admin/index.html in any of your templates folders to override the original template and modify it to show the counts:

{% extends "admin/base_site.html" %} 
{% load i18n %} 

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% load adminmedia %}{% admin_media_prefix %}css/dashboard.css" />{% endblock %} 

{% block coltype %}colMS{% endblock %} 

{% block bodyclass %}dashboard{% endblock %} 

{% block breadcrumbs %}{% endblock %} 

{% block content %}
<div id="content-main">

{% if app_list %}
    {% for app in app_list %}
        <div class="module">
        <table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}">
        <caption><a href="{{ app.app_url }}" class="section">{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</a></caption>
        {% for model in app.models %}
            <tr>
              <th scope="row">
                {% if model.perms.change %}
                    <a href="{{ model.admin_url }}">{{ model.name }}</a>
                {% else %}
                    {{ model.name }}
                {% endif %}
                ({{ model.count }})
              </th>

            {% if model.perms.add %}
                <td><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
            {% else %}
                <td>&nbsp;</td>
            {% endif %}

            {% if model.perms.change %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td>&nbsp;</td>
            {% endif %}
            </tr>
        {% endfor %}
        </table>
        </div>
    {% endfor %}
{% else %}
    <p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}

{% block sidebar %}
<div id="content-related">
    <div class="module" id="recent-actions-module">
        <h2>{% trans 'Recent Actions' %}</h2>
        <h3>{% trans 'My Actions' %}</h3>
            {% load log %}
            {% get_admin_log 10 as admin_log for_user user %}
            {% if not admin_log %}
            <p>{% trans 'None available' %}</p>
            {% else %}
            <ul class="actionlist">
            {% for entry in admin_log %}
            <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
                {% if entry.is_deletion %}
                    {{ entry.object_repr }}
                {% else %}
                    <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
                {% endif %}
                <br/>
                {% if entry.content_type %}
                    <span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span>
                {% else %}
                    <span class="mini quiet">{% trans 'Unknown content' %}</span>
                {% endif %}
            </li>
            {% endfor %}
            </ul>
            {% endif %}
    </div>
</div>
{% endblock %}

This will do it. (You will still need to modify the app_index view to see the counts correctly in the app index pages, I leave this as an exercise to you :-)


A 2022 update using Django 4.0

  1. Subclass the default admin site, see the official Django doc on subclassing the AdminSite.
  2. in the subclass, overwrite the _build_app_dict() method to add count in its model_dict as in:
model_dict = {
  "name": capfirst(model._meta.verbose_name_plural),
  "object_name": model._meta.object_name,
  "perms": perms,
  "admin_url": None,
  "add_url": None,
  "count": model.objects.count(), # THIS IS ALL YOU NEED TO ADD
}
  1. Override the default admin site for your project with the subclass that we have created and optimized. see the official Django doc overriding the default admin site.
  2. Override the app_list.html template if you haven't already. Inside your app_list.html template, you can now use the model.count variable like so {{ model.count }}. see the official Django docs on overriding templates.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜