Added support for queryset() overrides on admin classes and inline admin classes.

Updated version to 1.4.5.
Updated README with explanation of requirements for overriding queryset() on inline models.
Added extra models to sample project to demonstrate sortable models with custom querysets.
Improved JavaScript of sortables to be more efficient with better comparison checking.
Fixed highlighting of stacked inlines on sort finish.
This commit is contained in:
Brandon Taylor
2013-04-27 22:58:02 -04:00
parent b6e68fa367
commit 014f6d1660
16 changed files with 477 additions and 68 deletions
+31 -1
View File
@@ -2,12 +2,42 @@ from django.contrib import admin
from adminsortable.admin import (SortableAdmin, SortableTabularInline,
SortableStackedInline, SortableGenericStackedInline)
from app.models import Category, Project, Credit, Note, GenericNote
from adminsortable.utils import get_is_sortable
from app.models import (Category, Widget, Project, Credit, Note, GenericNote,
Component)
admin.site.register(Category, SortableAdmin)
class ComponentInline(SortableStackedInline):
model = Component
def queryset(self, request):
qs = super(ComponentInline, self).queryset(request).exclude(title__icontains='2')
if get_is_sortable(qs):
self.model.is_sortable = True
else:
self.model.is_sortable = False
return qs
class WidgetAdmin(SortableAdmin):
def queryset(self, request):
"""
A simple example demonstrating that adminsortable works even in
situations where you need to filter the queryset in admin. Here,
we are just filtering out `widget` instances with an pk higher
than 3
"""
qs = super(WidgetAdmin, self).queryset(request)
return qs.filter(id__lte=3)
inlines = [ComponentInline]
admin.site.register(Widget, WidgetAdmin)
class CreditInline(SortableTabularInline):
model = Credit
@@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Category'
db.create_table(u'app_category', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
))
db.send_create_signal(u'app', ['Category'])
# Adding model 'Project'
db.create_table(u'app_project', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
('category', self.gf('adminsortable.fields.SortableForeignKey')(to=orm['app.Category'])),
('description', self.gf('django.db.models.fields.TextField')()),
))
db.send_create_signal(u'app', ['Project'])
# Adding model 'Credit'
db.create_table(u'app_credit', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['app.Project'])),
('first_name', self.gf('django.db.models.fields.CharField')(max_length=30)),
('last_name', self.gf('django.db.models.fields.CharField')(max_length=30)),
))
db.send_create_signal(u'app', ['Credit'])
# Adding model 'Note'
db.create_table(u'app_note', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['app.Project'])),
('text', self.gf('django.db.models.fields.CharField')(max_length=100)),
))
db.send_create_signal(u'app', ['Note'])
# Adding model 'GenericNote'
db.create_table(u'app_genericnote', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='generic_notes', to=orm['contenttypes.ContentType'])),
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
))
db.send_create_signal(u'app', ['GenericNote'])
def backwards(self, orm):
# Deleting model 'Category'
db.delete_table(u'app_category')
# Deleting model 'Project'
db.delete_table(u'app_project')
# Deleting model 'Credit'
db.delete_table(u'app_credit')
# Deleting model 'Note'
db.delete_table(u'app_note')
# Deleting model 'GenericNote'
db.delete_table(u'app_genericnote')
models = {
u'app.category': {
'Meta': {'ordering': "['order']", 'object_name': 'Category'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.credit': {
'Meta': {'ordering': "['order']", 'object_name': 'Credit'},
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['app.Project']"})
},
u'app.genericnote': {
'Meta': {'ordering': "['order']", 'object_name': 'GenericNote'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'generic_notes'", 'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.note': {
'Meta': {'ordering': "['order']", 'object_name': 'Note'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['app.Project']"}),
'text': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'app.project': {
'Meta': {'ordering': "['order']", 'object_name': 'Project'},
'category': ('adminsortable.fields.SortableForeignKey', [], {'to': u"orm['app.Category']"}),
'description': ('django.db.models.fields.TextField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['app']
@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Widget'
db.create_table(u'app_widget', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
))
db.send_create_signal(u'app', ['Widget'])
def backwards(self, orm):
# Deleting model 'Widget'
db.delete_table(u'app_widget')
models = {
u'app.category': {
'Meta': {'ordering': "['order']", 'object_name': 'Category'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.credit': {
'Meta': {'ordering': "['order']", 'object_name': 'Credit'},
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['app.Project']"})
},
u'app.genericnote': {
'Meta': {'ordering': "['order']", 'object_name': 'GenericNote'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'generic_notes'", 'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.note': {
'Meta': {'ordering': "['order']", 'object_name': 'Note'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['app.Project']"}),
'text': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'app.project': {
'Meta': {'ordering': "['order']", 'object_name': 'Project'},
'category': ('adminsortable.fields.SortableForeignKey', [], {'to': u"orm['app.Category']"}),
'description': ('django.db.models.fields.TextField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.widget': {
'Meta': {'ordering': "['order']", 'object_name': 'Widget'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['app']
@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Component'
db.create_table(u'app_component', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
('widget', self.gf('adminsortable.fields.SortableForeignKey')(to=orm['app.Widget'])),
))
db.send_create_signal(u'app', ['Component'])
def backwards(self, orm):
# Deleting model 'Component'
db.delete_table(u'app_component')
models = {
u'app.category': {
'Meta': {'ordering': "['order']", 'object_name': 'Category'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.component': {
'Meta': {'ordering': "['order']", 'object_name': 'Component'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'widget': ('adminsortable.fields.SortableForeignKey', [], {'to': u"orm['app.Widget']"})
},
u'app.credit': {
'Meta': {'ordering': "['order']", 'object_name': 'Credit'},
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['app.Project']"})
},
u'app.genericnote': {
'Meta': {'ordering': "['order']", 'object_name': 'GenericNote'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'generic_notes'", 'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.note': {
'Meta': {'ordering': "['order']", 'object_name': 'Note'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['app.Project']"}),
'text': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'app.project': {
'Meta': {'ordering': "['order']", 'object_name': 'Project'},
'category': ('adminsortable.fields.SortableForeignKey', [], {'to': u"orm['app.Category']"}),
'description': ('django.db.models.fields.TextField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'app.widget': {
'Meta': {'ordering': "['order']", 'object_name': 'Widget'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['app']
+26 -6
View File
@@ -16,7 +16,7 @@ class SimpleModel(models.Model):
return self.title
#a model that is sortable
# A model that is sortable
class Category(SimpleModel, Sortable):
class Meta(Sortable.Meta):
"""
@@ -27,8 +27,17 @@ class Category(SimpleModel, Sortable):
verbose_name_plural = 'Categories'
#a model that is sortable relative to a foreign key that is also sortable
#uses SortableForeignKey field. Works with versions 1.3+
# A model with an override of its queryset for admin
class Widget(SimpleModel, Sortable):
class Meta(Sortable.Meta):
pass
def __unicode__(self):
return self.title
# A model that is sortable relative to a foreign key that is also sortable
# uses SortableForeignKey field. Works with versions 1.3+
class Project(SimpleModel, Sortable):
class Meta(Sortable.Meta):
pass
@@ -37,7 +46,7 @@ class Project(SimpleModel, Sortable):
description = models.TextField()
#registered as a tabular inline on `Project`
# Registered as a tabular inline on `Project`
class Credit(Sortable):
class Meta(Sortable.Meta):
pass
@@ -50,7 +59,7 @@ class Credit(Sortable):
return '{0} {1}'.format(self.first_name, self.last_name)
#registered as a stacked inline on `Project`
# Registered as a stacked inline on `Project`
class Note(Sortable):
class Meta(Sortable.Meta):
pass
@@ -62,7 +71,7 @@ class Note(Sortable):
return self.text
#a generic bound model
# A generic bound model
class GenericNote(SimpleModel, Sortable):
content_type = models.ForeignKey(ContentType,
verbose_name=u"Content type", related_name="generic_notes")
@@ -75,3 +84,14 @@ class GenericNote(SimpleModel, Sortable):
def __unicode__(self):
return u'{0} : {1}'.format(self.title, self.content_object)
# An model registered as an inline that has a custom queryset
class Component(SimpleModel, Sortable):
class Meta(Sortable.Meta):
pass
widget = SortableForeignKey(Widget)
def __unicode__(self):
return self.title