Makes models orderable on the change list page of the admin using drag and drop with jQuery UI (via sortable()). So you can order your objects in more easy way.
Inspired by snippets #1053 and #998
First, ordering field to your model (default called 'order). You can specify other name for this field, but you should add 'order_field' attr to model (i.e order_field = 'your_new_order_field_name')
Also, snippet adds 'order_link' field to admin's changelist and hides it by javascript.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | # 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 '<a href="%s" class="order_link">%s</a>' % (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<model_type_id>\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)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Thanks!
bug on line 9: s/MenuManager/MenuItemManager/
It'd also be helpful to put a comma at the end of the urls.py line (when copying it's easy to neglect to put in ones own comma). Thanks again.
#
Thank you for reply. i've fixed typos :)
#
how do I get rid of "CSRF verification failed. Request aborted." error? I tried decorating the order view with @csrf_exempt - no cure :(
#
Never mind my comment :) Fixed that.
#
Please login first before commenting.