Задать вопрос

Тел: +7 965 3737 888

669

Просмотров

17

Ответов

Orderable inlines using drag and drop with jQuery UI

An easy way of making inlines orderable using drag-and-drop, using jQuery UI's sortable() plugin.

First, add an "order" field to the inline models which is an IntegerField, and set that model to use 'order' as its default order_by.

Then hook in the JavaScript. This should make them drag-and-drop sortable using jQuery UI, and also hide the divs containing those order fields once the page has loaded. This technique is unobtrusive: if JavaScript is disabled, the order fields will be visible and the user will be able to manually set the order by entering numbers themselves.

Вопрос полезен? Да0/Нет0
file_2738.py(1.6Кб)
None

Ответы (17):

Ответpayala:24.08.2010
Ответ полезен? Да0/Нет0

I had to modify the following in order to hide the order field in Django 1.2.1.

I changed the line:

$(this).find('input[id$=order]').parent('div').parent('div').hide().parent().parent().css('cursor','move');

to:

$(this).find('input[id$=order]').parent('td').hide().parent('tr').parent('tbody').parent('table').find("th:contains('Order')").hide(); $(this).find('input[id$=order]').parent('td').hide().parent('tr').parent('tbody').parent('table').css('cursor','move');

Ответmetamemetics:19.05.2010
Ответ полезен? Да0/Нет0

A quick hack of eddified's post to work with Django 1.2 and update the order field with dynamic inline creation:

jQuery(function($) {
    $("div.inline-group").sortable({ 
        axis: 'y',
        placeholder: 'ui-state-highlight', 
        forcePlaceholderSize: 'true', 
        items: '.row1, .row2', 
        update: update
    });
    $("div.inline-group").disableSelection();
});
function update() {
    $('.row1, .row2').each(function(i) {
        $(this).find('input[id$=order]').val(i+1);
    });
}
jQuery(document).ready(function($){
    $(this).find('input[id$=order]').parent('div').parent('div').hide().parent().parent().css('cursor','move');
    $('.add-row a').click(update);
});

Ответeddified:09.04.2010
Ответ полезен? Да0/Нет0

replace ALL occurrences of "parent_order" with just "order" in my previous post.

Ответeddified:09.04.2010
Ответ полезен? Да0/Нет0

I used leplatrem's June 26 comment but I had to change the first line to this:

jQuery(function($) {

because something else in the page called jquery.noConflict() and it was messing up use of the dollar sign.

I also had to change vTextField to vIntegerField -- not sure why I had to do this, maybe it has to do with my django version, which is 1.2.0 beta 1

And then I also changed this:

$(this).find('input[id$=parent_order]').parent('div').parent('div').hide();

to this:

$(this).find('input[id$=parent_order]').parent('div').parent('div').hide().parent().parent().css('cursor','move');

Which helps the user know that the items are orderable (otherwise there is no indication in the U.I. that the items are orderable).

Here is my final code:

jQuery(function($) {
    $("div.inline-group").sortable({ 
        //axis: 'y',
        placeholder: 'ui-state-highlight', 
        forcePlaceholderSize: 'true', 
        items: 'div.inline-related', 
        update: function() {
            $(this).find('div.inline-related').each(function(i) {
                if ($(this).find('.vIntegerField').val()) {
                    $(this).find('input[id$=parent_order]').val(i+1);
                }
        });
        }
    });
    $("div.inline-group").disableSelection();

});

jQuery(document).ready(function($){
    $(this).find('input[id$=parent_order]').parent('div').parent('div').hide().parent().parent().css('cursor','move');
});

Ответugurozyilmazel:26.02.2010
Ответ полезен? Да0/Нет0

thanx a lot!

Ответbalexand:30.12.2009
Ответ полезен? Да0/Нет0

The script above doesn't set the order fields properly if the fields are moved before the name has been entered. It's easier to just update the order fields before the form submits like this:

/* menu-sort.js */

jQuery(function($) {
    $('div.inline-group').sortable({
        /*containment: 'parent',
        zindex: 10, */
        items: 'div.inline-related',
        handle: 'h3:first'
    });
    $('div.inline-related h3').css('cursor', 'move');
    $('div.inline-related').find('input[id$=order]').parent('div').hide();
    $('#menu_form').submit(function() {
        $('div.inline-group > div.inline-related').each(function(i) {
            if ($(this).find('input[id$=name]').val()) {
                $(this).find('input[id$=order]').val(i+1);
            }
        });
    });
});

Ответdfolland:13.10.2009
Ответ полезен? Да0/Нет0

for vedran: "name" and "order" are 2 required fields in the original code. Use leplatrem's code (June 26) which only requires "order"

Ответvedran:16.07.2009
Ответ полезен? Да0/Нет0

cant make markdown working...

Ответvedran:16.07.2009
Ответ полезен? Да0/Нет0

hi! my item model has two ForeignKey fields and ordering is working but when i save the form it rearanges as in initial situation, as no ordering was made after making a few entries. does someone has a hint?

here is my 'Item' class from model.py

class PhotoSetPhotoItem(models.Model): #mid = models.AutoField(primary_key=True) order = models.IntegerField(blank = True, null = True) photo_set = models.ForeignKey('PhotoSet', related_name='photoset') photo_item = models.ForeignKey('Photo', related_name='photoitem') class Meta: #db_table='photoset_photoitems' ordering = ['order']

def __unicode__(self):
    return str(self.order)+str(self.mid)

Ответleplatrem:26.06.2009
Ответ полезен? Да0/Нет0

I managed to adapt it. Your critics about this piece of javascript are warmly welcomed!

$(function() {
    $("div.inline-group").sortable({ 
        //axis: 'y',
        placeholder: 'ui-state-highlight', 
        forcePlaceholderSize: 'true', 
        items: 'div.inline-related', 
        update: function() {
            $(this).find('div.inline-related').each(function(i) {
                if ($(this).find('.vTextField').val()) {
                    $(this).find('input[id$=order]').val(i+1);
                }
        });
        }
    });
    $("div.inline-group").disableSelection();

});

jQuery(document).ready(function($){
    $(this).find('input[id$=order]').parent('div').parent('div').hide()
});

Ответsouthern_sun:26.06.2009
Ответ полезен? Да0/Нет0

The following script works with TabularInline in latest django release:

    jQuery(function($) {
        $('div.inline-group').sortable({
            items: 'tr.has_original',
            handle: 'td',
            update: function() {
                $(this).find('tr.has_original').each(function(i) {
                    $(this).find('input[name$=order]').val(i+1);
                    $(this).removeClass('row1').removeClass('row2');
                    $(this).addClass('row'+((i%2)+1));
                });
            }
        });
        $('tr.has_original').css('cursor', 'move');
    });

Ответleplatrem:26.06.2009
Ответ полезен? Да0/Нет0

At first, it looked pretty easy. But, I realized the menu-sort.js was made for an older version of Django.

With django1.02, inline items in the automatic admin look like:

<div class="inline-group">
<h2>Items</h2>
<div class="inline-related">
  <h3><b>Item:</b>Coffee</h3>
  <fieldset class="module aligned">
  <div class="form-row name">...</div>
  <div class="form-row order">...</div>
</div>
</div>

Does anyone already worked on updating menu-sort.js ?

Thank you all

Ответandybak:05.01.2009
Ответ полезен? Да0/Нет0

This should work for TabularInlines. You might want to tweak my choice of handle and you'll have to change the eq(5) in the last line depending where in the field list you have placed 'order':

jQuery(function($) {
    $('.module table').sortable({
        items: 'tr',
        handle: 'td.title',
        update: function() {
            $(this).find('tr').each(function(i) {
                if ($(this).find('input[class$=vTextField]').val()) {
                    $(this).find('input[id$=order]').val(i+1);
                }
            });
        }
    });
    $('.module td.title').css('cursor', 'move');
    $('.module table').find('input[id$=order]').parent('td').hide();
    $('.module table thead th:eq(5)').hide();
});

Ответtrey:19.12.2008
Ответ полезен? Да0/Нет0

If you change line 63 (menu-sort.js) to

$(this).find('div.inline-related').not('div.inline-related:last').each(function(i) {

and then remove the if statement, It's a little less brittle in terms of field names (as it is here it requires a name field in the inline model.

Ответpatrickk:23.10.2008
Ответ полезен? Да0/Нет0

ordering is lost if there´s an error somewhere in the form.

Ответexogen:14.09.2008
Ответ полезен? Да0/Нет0

Nice! Just a note for anyone who was confused like I was - the JavaScript only works on StackedInlines, not TabularInlines.

Ответrichardh:13.09.2008
Ответ полезен? Да0/Нет0

Great presentation at PyCon UK 2008 this morning Simon. I have been wondering how do this for a year!