Refactored sortable_by into a property instead of a classmethod.
Added backwards compatibility for pre 1.1.1 versions that still have sortable_by defined as a classmethod. Need to address dynamic regroup template tag to see why categories are not being grouped properly in sample app.master
parent
fba568399c
commit
1b9c5c0a64
|
|
@ -53,13 +53,18 @@ class SortableAdmin(ModelAdmin):
|
||||||
has_perm = request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
|
has_perm = request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
|
||||||
objects = self.model.objects.all()
|
objects = self.model.objects.all()
|
||||||
|
|
||||||
"""
|
#Determine if we need to regroup objects relative to a foreign key specified on the
|
||||||
Determine if we need to regroup objects relative to a foreign key specified on the
|
# model class that is extending Sortable.
|
||||||
model class that is extending Sortable.
|
|
||||||
"""
|
|
||||||
sortable_by = getattr(self.model, 'sortable_by', None)
|
sortable_by = getattr(self.model, 'sortable_by', None)
|
||||||
if sortable_by:
|
if sortable_by:
|
||||||
sortable_by_class, sortable_by_expression = sortable_by()
|
#backwards compatibility for < 1.1.1, where sortable_by was a classmethod instead of a property
|
||||||
|
try:
|
||||||
|
sortable_by_class, sortable_by_expression = sortable_by()
|
||||||
|
except ValueError:
|
||||||
|
sortable_by_class = self.model.sortable_by
|
||||||
|
sortable_by_expression = sortable_by_class.__name__.lower()
|
||||||
|
|
||||||
|
print sortable_by_expression
|
||||||
sortable_by_class_display_name = sortable_by_class._meta.verbose_name_plural
|
sortable_by_class_display_name = sortable_by_class._meta.verbose_name_plural
|
||||||
sortable_by_class_is_sortable = sortable_by_class.is_sortable()
|
sortable_by_class_is_sortable = sortable_by_class.is_sortable()
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,12 @@ class Sortable(models.Model):
|
||||||
`model_type_id` returns the ContentType.id for the Model that inherits Sortable
|
`model_type_id` returns the ContentType.id for the Model that inherits Sortable
|
||||||
|
|
||||||
`save` the override of save increments the last/highest value of order by 1
|
`save` the override of save increments the last/highest value of order by 1
|
||||||
|
|
||||||
|
Override `sortable_by` method to make your model be sortable by a foreign key field.
|
||||||
|
Set `sortable_by` to the class specified in the foreign key relationship.
|
||||||
"""
|
"""
|
||||||
order = models.PositiveIntegerField(editable=False, default=1, db_index=True)
|
order = models.PositiveIntegerField(editable=False, default=1, db_index=True)
|
||||||
|
sortable_by = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
{% if objects %}
|
{% if objects %}
|
||||||
<div id="sortable">
|
<div id="sortable">
|
||||||
{% if group_expression %}
|
{% if group_expression %}
|
||||||
{% render_nested_sortable_objects objects group_expression %}
|
{% render_nested_sortable_objects objects group_expression %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% render_sortable_objects objects %}
|
{% render_sortable_objects objects %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ def dynamic_regroup(parser, token):
|
||||||
"""
|
"""
|
||||||
expression = lastbits_reversed[2][::-1]
|
expression = lastbits_reversed[2][::-1]
|
||||||
var_name = lastbits_reversed[0][::-1]
|
var_name = lastbits_reversed[0][::-1]
|
||||||
|
print expression
|
||||||
"""
|
"""
|
||||||
We also need to hand the parser to the node in order to convert the value
|
We also need to hand the parser to the node in order to convert the value
|
||||||
for `expression` to a FilterExpression.
|
for `expression` to a FilterExpression.
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from adminsortable.admin import SortableAdmin, SortableTabularInline, SortableStackedInline
|
from adminsortable.admin import SortableAdmin, SortableTabularInline, SortableStackedInline
|
||||||
from app.models import Category, Project, Credit, Note
|
from app.models import Category, Project, Credit, Note, Sample
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Category, SortableAdmin)
|
admin.site.register(Category, SortableAdmin)
|
||||||
|
|
@ -20,3 +20,4 @@ class ProjectAdmin(SortableAdmin):
|
||||||
list_display = ['__unicode__', 'category']
|
list_display = ['__unicode__', 'category']
|
||||||
|
|
||||||
admin.site.register(Project, ProjectAdmin)
|
admin.site.register(Project, ProjectAdmin)
|
||||||
|
admin.site.register(Sample, SortableAdmin)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
# encoding: 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 'Sample'
|
||||||
|
db.create_table('app_sample', (
|
||||||
|
('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('django.db.models.fields.related.ForeignKey')(to=orm['app.Category'])),
|
||||||
|
('description', self.gf('django.db.models.fields.TextField')()),
|
||||||
|
))
|
||||||
|
db.send_create_signal('app', ['Sample'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
|
||||||
|
# Deleting model 'Sample'
|
||||||
|
db.delete_table('app_sample')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'app.category': {
|
||||||
|
'Meta': {'ordering': "['order']", 'object_name': 'Category'},
|
||||||
|
'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'})
|
||||||
|
},
|
||||||
|
'app.credit': {
|
||||||
|
'Meta': {'ordering': "['order']", 'object_name': 'Credit'},
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||||
|
'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': "orm['app.Project']"})
|
||||||
|
},
|
||||||
|
'app.note': {
|
||||||
|
'Meta': {'ordering': "['order']", 'object_name': 'Note'},
|
||||||
|
'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': "orm['app.Project']"}),
|
||||||
|
'text': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'app.project': {
|
||||||
|
'Meta': {'ordering': "['order']", 'object_name': 'Project'},
|
||||||
|
'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['app.Category']"}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'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'})
|
||||||
|
},
|
||||||
|
'app.sample': {
|
||||||
|
'Meta': {'ordering': "['order']", 'object_name': 'Sample'},
|
||||||
|
'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['app.Category']"}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'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'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['app']
|
||||||
|
|
@ -29,13 +29,28 @@ class Project(SimpleModel, Sortable):
|
||||||
class Meta(Sortable.Meta):
|
class Meta(Sortable.Meta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@classmethod
|
# @classmethod
|
||||||
def sortable_by(cls):
|
# def sortable_by(cls):
|
||||||
return Category, 'category'
|
# return Category, 'category'
|
||||||
|
|
||||||
category = models.ForeignKey(Category)
|
category = models.ForeignKey(Category)
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
|
|
||||||
|
sortable_by = Category
|
||||||
|
|
||||||
|
|
||||||
|
#a model that is sortable relative to a foreign key that is also sortable
|
||||||
|
class Sample(SimpleModel, Sortable):
|
||||||
|
class Meta(Sortable.Meta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
category = models.ForeignKey(Category)
|
||||||
|
description = models.TextField()
|
||||||
|
|
||||||
|
#field to define which foreign key the model is sortable by.
|
||||||
|
#works with versions > 1.1.1
|
||||||
|
sortable_by = Category
|
||||||
|
|
||||||
|
|
||||||
#registered as a tabular inline on project
|
#registered as a tabular inline on project
|
||||||
class Credit(Sortable):
|
class Credit(Sortable):
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
import httplib
|
import httplib
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.contrib.auth.forms import authenticate, UserCreationForm
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.middleware import csrf
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.template.defaultfilters import urlencode
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client, RequestFactory
|
from django.test.client import Client, RequestFactory
|
||||||
|
|
||||||
|
|
@ -83,6 +80,9 @@ class SortableTestCase(TestCase):
|
||||||
def get_category_indexes(self, *categories):
|
def get_category_indexes(self, *categories):
|
||||||
return {'indexes' : ','.join([str(c.id) for c in categories])}
|
return {'indexes' : ','.join([str(c.id) for c in categories])}
|
||||||
|
|
||||||
|
def test_sortable_by_backwards_compatibility(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def test_adminsortable_changelist_templates(self):
|
def test_adminsortable_changelist_templates(self):
|
||||||
logged_in = self.client.login(username=self.user.username, password=self.user_raw_password)
|
logged_in = self.client.login(username=self.user.username, password=self.user_raw_password)
|
||||||
self.assertTrue(logged_in, 'User is not logged in')
|
self.assertTrue(logged_in, 'User is not logged in')
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,6 @@ MIDDLEWARE_CLASSES = (
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue