Permalink
Browse files

First commit

  • Loading branch information...
0 parents commit 0ba1de4d006fca1e9405cab3e5dc62310373dfc2 @claudiob claudiob committed Apr 8, 2011
Showing with 234 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +1 −0 AUTHORS
  3. +19 −0 LICENSE
  4. +1 −0 MANIFEST.in
  5. +52 −0 README.md
  6. +23 −0 setup.py
  7. +14 −0 sortable/__init__.py
  8. +9 −0 sortable/admin.py
  9. +18 −0 sortable/models.py
  10. +93 −0 sortable/templates/js/admin_list_reorder.js
@@ -0,0 +1,4 @@
+*.pyc
+sortable.egg-info/
+dist/
+build/
@@ -0,0 +1 @@
+Red Interactive Agency
19 LICENSE
@@ -0,0 +1,19 @@
+copyright (c) 2011 Red Interactive Agency
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
@@ -0,0 +1 @@
+include LICENSE README.md MANIFEST.in AUTHORS
@@ -0,0 +1,52 @@
+# Quick start guide
+
+## Download
+
+Using `pip`:
+
+ pip install -e git://github.com/ff0000/sortable.git#egg=sortable
+
+Using `git`:
+
+ git clone git://github.com/ff0000/sortable.git
+
+or download the package from [github.com/ff0000/sortable](https://github.com/ff0000/sortable).
+
+## Installation
+
+Open `settings.py` and add `sortable` to your `INSTALLED_APPS`:
+
+ INSTALLED_APPS = (
+ [...],
+ 'sortable',
+ )
+
+Copy the reorder Javascript the `static/js` folder:
+
+ cp [sortable folder]/sortable/static/js/admin_list_reorder.js [django-app]/static/js/
+
+## Reordering instances of a model with drag-and-drop in the admin
+
+To add the sortable feature a model called `Article` do the following:
+
+Edit `app/articles/models.py` changing `models.Model` with `Sortable`:
+
+ from sortable.models import Sortable
+
+ class Article(Sortable):
+ # here the model fields, Meta, etc.
+
+Edit `app/articles/admin.py` changing `admin.ModelAdmin` with `SortableAdmin`:
+
+ from sortable.admin import SortableAdmin
+
+ class ArticleAdmin(SortableAdmin):
+ # here the admin stuff
+
+If `ArticleAdmin` includes the `list_display` declaration, change it like this:
+
+ # Old version
+ list_display = ('__unicode__', ...,)
+ # New version
+ list_display = SortableAdmin.list_display + ('__unicode__', ...,)
+
@@ -0,0 +1,23 @@
+from setuptools import setup, find_packages
+
+setup(
+ name='sortable',
+ version='0.1',
+ description='An app to add drag-and-drop to Grappelli admin to reorder instances of models.',
+ author='Red Interactive Agency',
+ author_email='geeks@ff0000.com',
+ url='http://github.com/ff0000/sortable/',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ classifiers=[
+ 'Development Status :: 2 - Pre-Alpha',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Framework :: Django',
+ ]
+)
+
@@ -0,0 +1,14 @@
+VERSION = (0, 0, 1, "a", 1) # following PEP 386
+DEV_N = 1
+
+def get_version():
+ version = "%s.%s" % (VERSION[0], VERSION[1])
+ if VERSION[2]:
+ version = "%s.%s" % (version, VERSION[2])
+ if VERSION[3] != "f":
+ version = "%s%s%s" % (version, VERSION[3], VERSION[4])
+ if DEV_N:
+ version = "%s.dev%s" % (version, DEV_N)
+ return version
+
+__version__ = get_version()
@@ -0,0 +1,9 @@
+from django.contrib import admin
+
+class SortableAdmin(admin.ModelAdmin):
+ # Make instances reorderable
+ list_editable = ('position',)
+ list_display = ('position', )
+ class Media: js = ('js/admin_list_reorder.js',)
+
+
@@ -0,0 +1,18 @@
+from django.db import models
+
+class Sortable(models.Model):
+ # Make instances reorderable
+ position = models.IntegerField()
+
+ def save(self, *args, **kwargs):
+ model = self.__class__
+ if self.position is None:
+ try:
+ last = model.objects.order_by('-position')[0]
+ self.position = last.position + 1
+ except IndexError: self.position = 0
+ return super(Sortable, self).save(*args, **kwargs)
+
+ class Meta:
+ abstract = True
+ ordering = ('position',)
@@ -0,0 +1,93 @@
+// Drag and drop ordering of admin list elements for Grappelli
+// From http://djangosnippets.org/snippets/2306/
+// Adds drag-and-drop ordering of rows in the admin list view for Grappelli.
+// This is based on Snippet #2057 and fixes some bugs as well as switching to
+// jQuery/jQuery UI provided by Grappelli.
+// No additional files need to be installed.
+//
+// The model needs to have a field holding the position and that field has to
+// be made list_editable in the ModelAdmin. The changes of the ordering are
+// applied after clicking 'Save'.
+// Author:sjaensch
+
+django.jQuery(document).ready(function() {
+ // Set this to the name of the column holding the position
+ pos_field = 'position';
+
+ // Determine the column number of the position field
+ pos_col = null;
+
+ cols = django.jQuery('.changelist-results tbody tr:first').children()
+
+ for (i = 0; i < cols.length; i++) {
+ inputs = django.jQuery(cols[i]).find('input[name*=' + pos_field + ']')
+
+ if (inputs.length > 0) {
+ // Found!
+ pos_col = i;
+ break;
+ }
+ }
+
+ if (pos_col == null) {
+ return;
+ }
+
+ // Some visual enhancements
+ header = django.jQuery('.changelist-results thead tr').children()[pos_col]
+ django.jQuery(header).css('width', '1em')
+ django.jQuery(header).children('a').text('#')
+
+ // Hide position field
+ django.jQuery('.changelist-results tbody tr').each(function(index) {
+ pos_td = django.jQuery(this).children()[pos_col];
+ input = django.jQuery(pos_td).children('input').first();
+ input.hide();
+
+ label = django.jQuery('<strong>' + input.attr('value') + '</strong>');
+ django.jQuery(pos_td).append(label);
+ });
+
+ // Determine sorted column and order
+ sorted = django.jQuery('.changelist-results thead th.sorted');
+ sorted_col = django.jQuery('.changelist-results thead th').index(sorted);
+ sort_order = sorted.hasClass('descending') ? 'desc' : 'asc';
+
+ if (sorted_col != pos_col) {
+ // Sorted column is not position column, bail out
+ console.info("Sorted column is not %s, bailing out", pos_field);
+ return;
+ }
+
+ django.jQuery('.changelist-results tbody tr').css('cursor', 'move');
+
+ // Make tbody > tr sortable
+ django.jQuery('.changelist-results tbody').sortable({
+ axis: 'y',
+ items: 'tr',
+ cursor: 'move',
+ update: function(event, ui) {
+ item = ui.item;
+ items = django.jQuery(this).find('tr').get();
+
+ if (sort_order == 'desc') {
+ // Reverse order
+ items.reverse();
+ }
+
+ django.jQuery(items).each(function(index) {
+ pos_td = django.jQuery(this).children()[pos_col];
+ input = django.jQuery(pos_td).children('input').first();
+ label = django.jQuery(pos_td).children('strong').first();
+
+ input.attr('value', index);
+ label.text(index);
+ });
+
+ // Update row classes
+ django.jQuery(this).find('tr').removeClass('row1').removeClass('row2');
+ django.jQuery(this).find('tr:even').addClass('row1');
+ django.jQuery(this).find('tr:odd').addClass('row2');
+ }
+ });
+});

0 comments on commit 0ba1de4

Please sign in to comment.