Index: django/contrib/admin/media/css/global.css
===================================================================
--- django/contrib/admin/media/css/global.css	(revision 3399)
+++ django/contrib/admin/media/css/global.css	(working copy)
@@ -135,6 +135,8 @@
 .object-tools a.viewsitelink:hover, .object-tools a.golink:hover { background:#5b80b2 url(../img/admin/tooltag-arrowright_over.gif) top right no-repeat; }
 .object-tools a.addlink { background:#999 url(../img/admin/tooltag-add.gif) top right no-repeat; padding-right:28px; }
 .object-tools a.addlink:hover { background:#5b80b2 url(../img/admin/tooltag-add_over.gif) top right no-repeat; }
+.object-tools a.deletelink { background:#999 url(../img/admin/tooltag-delete.gif) top right no-repeat; padding-right:28px; }
+.object-tools a.deletelink:hover { background:#5b80b2 url(../img/admin/tooltag-delete_over.gif) top right no-repeat; }
 
 /* OBJECT HISTORY */
 table#change-history { width:100%; }
Index: django/contrib/admin/templatetags/admin_list.py
===================================================================
--- django/contrib/admin/templatetags/admin_list.py	(revision 3399)
+++ django/contrib/admin/templatetags/admin_list.py	(working copy)
@@ -68,7 +68,7 @@
     }
 pagination = register.inclusion_tag('admin/pagination.html')(pagination)
 
-def result_headers(cl):
+def result_headers(cl, user):
     lookup_opts = cl.lookup_opts
 
     for i, field_name in enumerate(lookup_opts.admin.list_display):
@@ -102,8 +102,11 @@
                        "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 '')}
+    delete_permission = '%s.%s' % (cl.model._meta.app_label, cl.opts.get_delete_permission())
+    if user.get_all_permissions().__contains__(delete_permission):
+        yield{"text":"Delete?"}
 
-def items_for_result(cl, result):
+def items_for_result(cl, result, user):
     first = True
     pk = cl.lookup_opts.pk.attname
     for field_name in cl.lookup_opts.admin.list_display:
@@ -175,15 +178,18 @@
                 (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag))
         else:
             yield ('<td%s>%s</td>' % (row_class, result_repr))
+    delete_permision = '%s.%s' % (cl.model._meta.app_label, cl.opts.get_delete_permission())
+    if user.get_all_permissions().__contains__(delete_permision):
+        yield('<td><input type="checkbox" name="%s" /></td>' % result_id)
 
-def results(cl):
+def results(cl, user):
     for res in cl.result_list:
-        yield list(items_for_result(cl,res))
+        yield list(items_for_result(cl,res, user))
 
-def result_list(cl):
+def result_list(cl, user):
     return {'cl': cl,
-            'result_headers': list(result_headers(cl)),
-            'results': list(results(cl))}
+            'result_headers': list(result_headers(cl, user)),
+            'results': list(results(cl, user))}
 result_list = register.inclusion_tag("admin/change_list_results.html")(result_list)
 
 def date_hierarchy(cl):
Index: django/contrib/admin/urls.py
===================================================================
--- django/contrib/admin/urls.py	(revision 3399)
+++ django/contrib/admin/urls.py	(working copy)
@@ -31,6 +31,7 @@
     # Add/change/delete/history
     ('^([^/]+)/([^/]+)/$', 'django.contrib.admin.views.main.change_list'),
     ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),
+    ('^([^/]+)/([^/]+)/delete/$', 'django.contrib.admin.views.main.delete_checked'),
     ('^([^/]+)/([^/]+)/(.+)/history/$', 'django.contrib.admin.views.main.history'),
     ('^([^/]+)/([^/]+)/(.+)/delete/$', 'django.contrib.admin.views.main.delete_stage'),
     ('^([^/]+)/([^/]+)/(.+)/$', 'django.contrib.admin.views.main.change_stage'),
Index: django/contrib/admin/views/main.py
===================================================================
--- django/contrib/admin/views/main.py	(revision 3399)
+++ django/contrib/admin/views/main.py	(working copy)
@@ -81,7 +81,7 @@
             myappend('_' + item)
     return "".join(res)
 
-def get_javascript_imports(opts, auto_populated_fields, field_sets):
+def get_javascript_imports(opts, auto_populated_fields, field_sets, has_delete_permission):
 # Put in any necessary JavaScript imports.
     js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
     if auto_populated_fields:
@@ -92,6 +92,8 @@
         js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
     if opts.admin.js:
         js.extend(opts.admin.js)
+    if has_delete_permission:
+        js.extend(['js/admin/delete.js'])
     seen_collapse = False
     for field_set in field_sets:
         if not seen_collapse and 'collapse' in field_set.classes:
@@ -209,7 +211,7 @@
         'auto_populated_fields': auto_populated_fields,
         'bound_field_sets': bound_field_sets,
         'first_form_field_id': first_form_field_id,
-        'javascript_imports': get_javascript_imports(opts, auto_populated_fields, field_sets),
+        'javascript_imports': get_javascript_imports(opts, auto_populated_fields, field_sets, context['perms'][app_label][opts.get_delete_permission()]),
         'ordered_objects': ordered_objects,
         'inline_related_objects': inline_related_objects,
         'form_url': form_url,
@@ -731,6 +733,9 @@
 
 def change_list(request, app_label, model_name):
     model = models.get_model(app_label, model_name)
+    opts = model._meta
+    auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
+    field_sets = opts.admin.get_field_sets(opts)
     if model is None:
         raise Http404, "App %r, model %r, not found" % (app_label, model_name)
     if not request.user.has_perm(app_label + '.' + model._meta.get_change_permission()):
@@ -752,7 +757,20 @@
         'cl': cl,
     })
     c.update({'has_add_permission': c['perms'][app_label][cl.opts.get_add_permission()]}),
+    c.update({'has_delete_permission': c['perms'][app_label][cl.opts.get_delete_permission()]}),
+    c.update({'javascript_imports': get_javascript_imports(opts, auto_populated_fields, field_sets, c['perms'][app_label][opts.get_delete_permission()])}),
     return render_to_response(['admin/%s/%s/change_list.html' % (app_label, cl.opts.object_name.lower()),
                                'admin/%s/change_list.html' % app_label,
                                'admin/change_list.html'], context_instance=c)
 change_list = staff_member_required(never_cache(change_list))
+
+def delete_checked(request, app_name, model_name):
+    if request.POST:
+        model = models.get_model(app_name, model_name)
+        for item in request.POST:
+            ob = model.objects.get(id=item)
+            ob.delete()
+        return HttpResponseRedirect('/admin/%s/%s/' % (app_name, model_name))
+    else:
+        return HttpResponseRedirect('/admin/%s/%s/' % (app_name, model_name))
+    
Index: django/contrib/admin/templates/admin/change_list.html
===================================================================
--- django/contrib/admin/templates/admin/change_list.html	(revision 3399)
+++ django/contrib/admin/templates/admin/change_list.html	(working copy)
@@ -1,5 +1,9 @@
 {% extends "admin/base_site.html" %}
-{% load adminmedia admin_list i18n %}
+{% load adminmedia admin_list i18n admin_modify %}
+{% block extrahead %}{{ block.super }}
+<script type="text/javascript" src="../../../jsi18n/"></script>
+{% for js in javascript_imports %}{% include_admin_script js %}{% endfor %}
+{% endblock %}
 {% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %}
 {% block bodyclass %}change-list{% endblock %}
 {% block userlinks %}<a href="../../doc/">{% trans 'Documentation' %}</a> / <a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
@@ -7,14 +11,23 @@
 {% 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|escape as name %}Add {{ name }}{% endblocktrans %}</a></li></ul>
-{% endif %}
+<ul class="object-tools">
+	{% if has_add_permission %}
+		<li>
+			<a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name|escape as name %}Add {{ name }}{% endblocktrans %}</a>
+		</li>
+	{% endif %}
+	{% if has_delete_permission %}
+		<li>
+			<a href="#" onclick="javascript: delete_checked();" class="deletelink">{% blocktrans with cl.opts.verbose_name|escape as name %}Delete checked {{ name }}{% endblocktrans %}</a>
+		</li>
+	{% endif %}
+</ul>
 <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
 {% block search %}{% search_form cl %}{% endblock %}
 {% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %}
 {% block filters %}{% filters cl %}{% endblock %}
-{% block result_list %}{% result_list cl %}{% endblock %}
+{% block result_list %}{% result_list cl user %}{% endblock %}
 {% block pagination %}{% pagination cl %}{% endblock %}
 </div>
 </div>
Index: django/contrib/admin/templates/admin/change_list_results.html
===================================================================
--- django/contrib/admin/templates/admin/change_list_results.html	(revision 3399)
+++ django/contrib/admin/templates/admin/change_list_results.html	(working copy)
@@ -1,4 +1,5 @@
 {% if results %}
+<form name="delete_checked_form" method="POST" action="delete/">
 <table cellspacing="0">
 <thead>
 <tr>
@@ -14,4 +15,5 @@
 {% endfor %}
 </tbody>
 </table>
+</form>
 {% endif %}
