# models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
class MenuItemManager(models.Manager):
def get_query_set(self):
return super(MenuItemManager, self).get_query_set().order_by("order", "id")
class MenuItem(models.Model):
name = models.CharField(max_length=100, blank=True, verbose_name="Name")
order = models.IntegerField(blank = True, null = True)
objects = MenuItemManager()
order_field = 'order' # You can specify your own field for sorting, but it's 'order' by default
class Meta:
db_table = u"menu"
def __unicode__(self):
return u"%s" % self.name
def order_link(self):
model_type_id = ContentType.objects.get_for_model(self.__class__).id
obj_id = self.id
kwargs = {"model_type_id": model_type_id}
url = reverse("admin_order", kwargs=kwargs)
return '%s' % (url, str(self.pk) or '')
order_link.allow_tags = True
order_link.short_description = 'Order' # If you change this you should change admin_sorting.js too
# urls.py
(r'^order/(?P\d+)/$', 'path.to.view', {}, 'admin_order'),
# views.py
from django.http import HttpResponseRedirect, HttpResponse
from django.contrib.contenttypes.models import ContentType
def order(request, model_type_id=None):
if not request.is_ajax() or not request.method == "POST":
return HttpResponse("BAD")
try:
indexes = request.POST.get('indexes', []).split(",")
klass = ContentType.objects.get(id=model_type_id).model_class()
order_field = getattr(klass, 'order_field', 'order')
objects_dict = dict([(obj.pk, obj) for obj in klass.objects.filter(pk__in=indexes)])
min_index = min(objects_dict.values(), key=lambda x: getattr(x, order_field))
min_index = getattr(min_index, order_field) or 0
for index in indexes:
obj = objects_dict[int(index)]
setattr(obj, order_field, min_index)
obj.save()
min_index += 1
except IndexError:
pass
except klass.DoesNotExist:
pass
except AttributeError:
pass
return HttpResponse()
# admin_sorting.js
$(function() {
$("#content-main").sortable({
axis: 'y',
items: '.row1, .row2',
stop: function(event, ui) {
var indexes = Array();
var url = "";
$("#content-main").find(".row1, .row2").each(function(i){
var id = $(this).find('.order_link').html();
// the bad way i know.
url = $(this).find('.order_link').attr('href');
indexes.push(id);
});
$.ajax({
url: url,
type: 'POST',
data: {
indexes: indexes.join(","),
}
});
},
});
$('#content-main table tbody').find('.order_link').parent('td').hide();
/*
:contains(value) — value here must be the same as in model's
order_link.short_description
*/
$('#content-main table thead').find('th:contains("Order")').hide();
$("#content-main table tbody").disableSelection();
});
# admin.py
class MenuItemAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'order_link')
list_display_links = ('id', 'name')
ordering = ('order','id')
class Media:
js = ("js/jquery-1.4.2.min.js",
"js/jqueryui-custom-1.7.2.min.js",
"js/admin_sorting.js",)
admin.site.register(MenuItem, MenuItemAdmin)