Created
July 2, 2009 13:53
-
-
Save joshourisman/139475 to your computer and use it in GitHub Desktop.
Code to enable drag and drop reordering on a change_list in the Django admin. Currently causes a 'too many open files' error for some reason.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% extends "reversion/change_list.html" %} | |
{% load my_admin i18n %} | |
{% block extrahead %} | |
<script type="text/javascript" src="/media/static/js/jquery-1.3.2.js" /> | |
<script type="text/javascript" src="/media/static/js/jquery-ui-1.7.2.custom.min.js" /> | |
<script type="text/javascript" src="/media/static/js/change_list_sort.js" /> | |
{% endblock %} | |
{% block object-tools %} | |
<ul class="object-tools"> | |
<li><a href="#apply" id="apply_order">Apply re-ordering</a></li> | |
<li><a href="" id="cancel_order">Cancel re-ordering</a></li> | |
<li><a href="recover/" class="recoverlink">{% blocktrans with cl.opts.verbose_name_plural|escape as name %}Recover deleted {{name}}{% endblocktrans %}</a></li> | |
{% 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 %} | |
</ul> | |
{% endblock %} | |
{% block result_list %}{% result_list cl %}{% endblock %} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% if results %} | |
<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> | |
<tbody> | |
{% for result in results %} | |
<tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr> | |
{% endfor %} | |
</tbody> | |
</table> | |
{% endif %} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(document).ready(function($) { | |
$('#apply_order').parents('li').hide(); | |
$('#cancel_order').parents('li').hide(); | |
$('tbody').sortable({ | |
containment: 'parent', | |
opacity: 0.5, | |
items: 'tr', | |
update: function(event, ui) { | |
$(this).find('tr').each(function(i) { | |
$(this).children('td.order').text(i+1); | |
}); | |
$('#apply_order').parents('li').show(); | |
$('#cancel_order').parents('li').show(); | |
} | |
}); | |
$('tr').css('cursor', 'move'); | |
$('#apply_order').click(function() { | |
var ordering = []; | |
$('td.order').each(function() { | |
ordering.push($(this).attr('id')) | |
}); | |
$.post('reorder/', { 'ordering': ordering }); | |
$('#apply_order').parents('li').hide(); | |
$('#cancel_order').parents('li').hide(); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.http import HttpResponse | |
from django.db.models import get_model | |
def reorder(request, app_name, model_name): | |
model = get_model(app_name, model_name) | |
ordering = request.POST.lists()[0][1] | |
ordering = [int(order) for order in ordering] | |
for id in ordering: | |
object = model.objects.get(id=id) | |
object.order = ordering.index(object.id)+1 | |
print "%s: %s" % (object, object.order) | |
object.save() | |
return HttpResponse() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib.admin.templatetags.admin_list import result_headers | |
from django.db import models | |
from django.utils import dateformat | |
from django.utils.html import escape, conditional_escape | |
from django.utils.text import capfirst | |
from django.utils.safestring import mark_safe | |
from django.utils.translation import get_date_formats | |
from django.utils.encoding import force_unicode | |
from django.template import Library | |
register = Library() | |
def items_for_result(cl, result): | |
first = True | |
pk = cl.lookup_opts.pk.attname | |
for field_name in cl.list_display: | |
if field_name == "order": | |
row_class = ' class="order" id="%d"' % getattr(result, 'id') | |
else: | |
row_class = '' | |
try: | |
f = cl.lookup_opts.get_field(field_name) | |
except models.FieldDoesNotExist: | |
# For non-field list_display values, the value is either a method, | |
# property or returned via a callable. | |
try: | |
if callable(field_name): | |
attr = field_name | |
value = attr(result) | |
elif hasattr(cl.model_admin, field_name) and \ | |
not field_name == '__str__' and not field_name == '__unicode__': | |
attr = getattr(cl.model_admin, field_name) | |
value = attr(result) | |
else: | |
attr = getattr(result, field_name) | |
if callable(attr): | |
value = attr() | |
else: | |
value = attr | |
allow_tags = getattr(attr, 'allow_tags', False) | |
boolean = getattr(attr, 'boolean', False) | |
if boolean: | |
allow_tags = True | |
result_repr = _boolean_icon(value) | |
else: | |
result_repr = smart_unicode(value) | |
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 allow_tags: | |
result_repr = escape(result_repr) | |
else: | |
result_repr = mark_safe(result_repr) | |
else: | |
field_val = getattr(result, f.attname) | |
if isinstance(f.rel, models.ManyToOneRel): | |
if field_val is not None: | |
result_repr = escape(getattr(result, f.name)) | |
else: | |
result_repr = EMPTY_CHANGELIST_VALUE | |
# Dates and times are special: They're formatted in a certain way. | |
elif isinstance(f, models.DateField) or isinstance(f, models.TimeField): | |
if field_val: | |
(date_format, datetime_format, time_format) = get_date_formats() | |
if isinstance(f, models.DateTimeField): | |
result_repr = capfirst(dateformat.format(field_val, datetime_format)) | |
elif isinstance(f, models.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, models.BooleanField) or isinstance(f, models.NullBooleanField): | |
result_repr = _boolean_icon(field_val) | |
# DecimalFields are special: Zero-pad the decimals. | |
elif isinstance(f, models.DecimalField): | |
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 = escape(field_val) | |
if force_unicode(result_repr) == '': | |
result_repr = mark_safe(' ') | |
# If list_display_links not defined, add the link tag to the first field | |
if (first and not cl.list_display_links) or field_name in cl.list_display_links: | |
table_tag = {True:'th', False:'td'}[first] | |
first = False | |
url = cl.url_for_result(result) | |
# Convert the pk to something that can be used in Javascript. | |
# Problem cases are long ints (23L) and non-ASCII strings. | |
if cl.to_field: | |
attr = str(cl.to_field) | |
else: | |
attr = pk | |
result_id = repr(force_unicode(getattr(result, attr)))[1:] | |
yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ | |
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag)) | |
else: | |
yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr))) | |
def results(cl): | |
for res in cl.result_list: | |
yield list(items_for_result(cl,res)) | |
def result_list(cl): | |
return {'cl': cl, | |
'result_headers': list(result_headers(cl)), | |
'results': list(results(cl))} | |
result_list = register.inclusion_tag("core/change_list_results.html")(result_list) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment