piotrkilczuk / django-inline-ordering Goto Github PK
View Code? Open in Web Editor NEWDjango app to ease ordering of related data - enable Drag&Drop ordering in admin with just a few LOC
Home Page: http://github.com/centralniak
Django app to ease ordering of related data - enable Drag&Drop ordering in admin with just a few LOC
Home Page: http://github.com/centralniak
I order the items in the admin, but when I save the order is loaded back to the sorting before my "hand ordering". I guess there is a problem on the save function.
Originally reported by e-mail by Frederico C. (thanks!)
I tried your app but it didn't work out of the box. I had to change the init function to:
init: function(){
jQuery("div.inline-group").sortable({
axis: 'y',
placeholder: 'ui-state-highlight',
forcePlaceholderSize: 'true',
items: InlineOrdering.getOrderables(),
start: function(){ jQuery(this).css('min-height', jQuery(this).height()) },
update: function(){ InlineOrdering.update() }
});
jQuery("div.inline-group").disableSelection();
jQuery(this).find('div.inline_ordering_position').hide();
jQuery('.add-row a').click(function(){
InlineOrdering.update
});
},
Note also the add of the start event, that prevents a very annoying behavior in google chrome (the div shrinks in height and everything moves - very annoying).
You also need to add a bit of css:
/* custom.css */
.ui-sortable{ cursor: move }
.inline_ordering_position{ display: none }
and this is what I've done in admin.py - note the css dictionary:
from django.contrib.admin import StackedInline
from settings import ADMIN_MEDIA_PREFIX
class OrderableStackedInline(StackedInline):
"""Adds necessary media files to regular Django StackedInline"""
class Media:
js = (
'%sjs/jquery-ui.js' % ADMIN_MEDIA_PREFIX,
'%sjs/inline_ordering.js' % ADMIN_MEDIA_PREFIX,
)
css = {
'screen': ('%scss/custom.css' % ADMIN_MEDIA_PREFIX,)
}
This plugin only appears to work if you have a one-to-many (ForeignKey) relationship between Gallery and Images.
What if you have many Images that you use across different Gallerys (ie. a many-to-many field?). Using your example of Images and Gallery.
This will work:
class Gallery(models.Model):
images = ForeignKey(Image)
This won't:
class Gallery(models.Model):
images = ManyToManyField(Image)
I have the second setup, and I get the following error when implementing your code:
<class 'appname.models.Image'> has no ForeignKey to <class 'appname.models.Gallery'>
Maybe I have it set up incorrectly, but I followed your steps exactly.
Pasted from em@il -- thx for reporting...
var InlineOrdering = {
/**
* Get list of elements that can be reordered
*
* At this point, only already existent records can be reordered (ie. where pk != '')
*
* @return Array
* @todo Check if given record changed, and if so, make it reorderable
* @todo Primary key might not be 'id' - better selector needed
*
*/
getOrderables: function(){
return jQuery('div.inline-group .inline-related input[name$=id]:not([value=])').parent('.inline-related');
},
/**
* Inits the jQuery UI D&D
*
*/
init: function(){
jQuery("div.inline-group").sortable({
axis: 'y',
placeholder: 'ui-state-highlight',
forcePlaceholderSize: 'true',
items: InlineOrdering.getOrderables(),
update: InlineOrdering.update
});
jQuery("div.inline-group").disableSelection();
jQuery(this).find('div.position').hide();
jQuery('.add-row a').click(InlineOrdering.update);
/**
* Hiding all position labels/inputs.
*/
$('input[id$=position]').hide().parent().hide();
/**
* Adding the drag-cursor to the inline rows (parent + all children which are not <img>, <a> or <select>)
* with non-empty <select>-fields.
*/
var nonEmptyRows = $('div[class$=position]').find("select[value!='']").parent();
nonEmptyRows.parent().css('cursor','move');
nonEmptyRows.find('*').not('select, img, a').css('cursor','move');
InlineOrdering.update();//Call update for initial numbering
},
/**
* Updates the position field
*
*/
update: function(){
InlineOrdering.getOrderables().each(function(i){
jQuery(this).find('input[id$=position]').val(i + 1);
/**
* Numberizes the list starting with 1., 2. ...
*/
j = i + 1;
var label = $('div[class$=position]').find("select[value!='']").parent().children(':first-child')[i].innerHTML;
label = label[0].match(/\d+/) ? j + label.substr(1) : j + '. ' + label
$('div[class$=position]').find("select[value!='']").parent().children(':first-child')[i].innerHTML = label;
});
}
};
jQuery(function(){
InlineOrdering.init();
});
Right now the README says:
"Add 'inline-ordering' to INSTALLED_APPS tuple in settings file"
I think it should be 'inline_ordering'. It won't work otherwise.
Very messy at the moment
I want to base my inline form value on the choice I made in model admin form. How can I pass the model admin selected value into the inline
Is necessary to add by hand the jquery UI to base.html. I used this code
<script>(function($){jQuery = $.noConflict(true);})(django.jQuery);</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js"></script>
the INLINE_ORDERING_JS setting is not being used anywhere in the code
It required following changes in order to work in Fx 3.6.12 on Ubuntu (not tested on other browsers though)
//jQuery("div.inline-group").disableSelection();
jQuery('div.inline_ordering_position').hide();
TypeError: 'undefined' is not a function (evaluating 'InlineOrdering.jQuery("div.inline-group").sortable')
Is there a way of eliminating this issue?
The distro on PyPi is still using the version with the /media/ directory instead of /static/. Using pip install django-inline-ordering
leaves Django 1.3+ unable to collect the static file.
I found using Max() to determine the next position will bring in wrong values as soon as an instance with a position < Max() is deleted. Those gaps will not be closed by moving the existing ones one position back.
Therefore I'm doing the saving like this in the ModelAdmin (no custom save() method in the model itself anymore) :
class OrderableAdmin(admin.ModelAdmin):
def save_formset(self, request, form, formset, change):
instances = formset.save(commit = False)
nextPos = len(formset.queryset)
for i in instances:
if i.inline_ordering_position == None:
i.inline_ordering_position = nextPos
nextPos += 1
i.save()
formset.save_m2m()
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.