From 64b8b9dc390f7ff508d8a2b5272c14c4db423829 Mon Sep 17 00:00:00 2001 From: Brandon Taylor Date: Mon, 24 Aug 2015 08:04:05 -0400 Subject: [PATCH] Added model with custom order field and inline model with custom order field example. --- sample_project/app/admin.py | 13 +- sample_project/app/migrations/0001_initial.py | 203 ++++++++++++++++++ .../app/migrations/0002_auto_20150824_0702.py | 37 ++++ sample_project/app/migrations/__init__.py | 0 sample_project/app/models.py | 38 ++++ sample_project/database/test_project.sqlite | Bin 105472 -> 112640 bytes 6 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 sample_project/app/migrations/0001_initial.py create mode 100644 sample_project/app/migrations/0002_auto_20150824_0702.py create mode 100644 sample_project/app/migrations/__init__.py diff --git a/sample_project/app/admin.py b/sample_project/app/admin.py index 437b052..f575195 100644 --- a/sample_project/app/admin.py +++ b/sample_project/app/admin.py @@ -6,7 +6,8 @@ from adminsortable.admin import (SortableAdmin, SortableTabularInline, from adminsortable.utils import get_is_sortable from app.models import (Category, Widget, Project, Credit, Note, GenericNote, Component, Person, NonSortableCategory, SortableCategoryWidget, - SortableNonInlineCategory, NonSortableCredit, NonSortableNote) + SortableNonInlineCategory, NonSortableCredit, NonSortableNote, + CustomWidget, CustomWidgetComponent) admin.site.register(Category, SortableAdmin) @@ -93,4 +94,14 @@ class NonSortableCategoryAdmin(NonSortableParentAdmin): admin.site.register(NonSortableCategory, NonSortableCategoryAdmin) +class CustomWidgetComponentInline(SortableStackedInline): + model = CustomWidgetComponent + extra = 0 + + +class CustomWidgetAdmin(SortableAdmin): + inlines = [CustomWidgetComponentInline] + + admin.site.register(SortableNonInlineCategory, SortableAdmin) +admin.site.register(CustomWidget, CustomWidgetAdmin) diff --git a/sample_project/app/migrations/0001_initial.py b/sample_project/app/migrations/0001_initial.py new file mode 100644 index 0000000..fca30ca --- /dev/null +++ b/sample_project/app/migrations/0001_initial.py @@ -0,0 +1,203 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import adminsortable.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['order'], + 'verbose_name_plural': 'Categories', + }, + ), + migrations.CreateModel( + name='Component', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='Credit', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('first_name', models.CharField(max_length=30)), + ('last_name', models.CharField(max_length=30)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='GenericNote', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('object_id', models.PositiveIntegerField(verbose_name='Content id')), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ('content_type', models.ForeignKey(related_name='generic_notes', verbose_name='Content type', to='contenttypes.ContentType')), + ], + options={ + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='NonSortableCategory', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ], + options={ + 'abstract': False, + 'verbose_name': 'Non-Sortable Category', + 'verbose_name_plural': 'Non-Sortable Categories', + }, + ), + migrations.CreateModel( + name='NonSortableCredit', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('first_name', models.CharField(max_length=30)), + ('last_name', models.CharField(max_length=30)), + ], + ), + migrations.CreateModel( + name='NonSortableNote', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('text', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='Note', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('text', models.CharField(max_length=100)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='Person', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('first_name', models.CharField(max_length=50)), + ('last_name', models.CharField(max_length=50)), + ('is_board_member', models.BooleanField(default=False, verbose_name=b'Board Member')), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['order'], + 'verbose_name_plural': 'People', + }, + ), + migrations.CreateModel( + name='Project', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('description', models.TextField()), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ('category', adminsortable.fields.SortableForeignKey(to='app.Category')), + ], + options={ + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='SortableCategoryWidget', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ('non_sortable_category', adminsortable.fields.SortableForeignKey(to='app.NonSortableCategory')), + ], + options={ + 'ordering': ['order'], + 'verbose_name': 'Sortable Category Widget', + 'verbose_name_plural': 'Sortable Category Widgets', + }, + ), + migrations.CreateModel( + name='SortableNonInlineCategory', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ('non_sortable_category', adminsortable.fields.SortableForeignKey(to='app.NonSortableCategory')), + ], + options={ + 'ordering': ['order'], + 'verbose_name': 'Sortable Non-Inline Category', + 'verbose_name_plural': 'Sortable Non-Inline Categories', + }, + ), + migrations.CreateModel( + name='Widget', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('order', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='CustomWidget', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('custom_order_field', models.PositiveIntegerField(default=0, editable=False)), + ], + options={ + 'ordering': ['custom_order_field'], 'verbose_name': 'Custom Widget', 'verbose_name_plural': 'Custom Widgets' + }, + ), + migrations.AddField( + model_name='note', + name='project', + field=models.ForeignKey(to='app.Project'), + ), + migrations.AddField( + model_name='nonsortablenote', + name='project', + field=models.ForeignKey(to='app.Project'), + ), + migrations.AddField( + model_name='nonsortablecredit', + name='project', + field=models.ForeignKey(to='app.Project'), + ), + migrations.AddField( + model_name='credit', + name='project', + field=models.ForeignKey(to='app.Project'), + ), + migrations.AddField( + model_name='component', + name='widget', + field=adminsortable.fields.SortableForeignKey(to='app.Widget'), + ), + ] diff --git a/sample_project/app/migrations/0002_auto_20150824_0702.py b/sample_project/app/migrations/0002_auto_20150824_0702.py new file mode 100644 index 0000000..c8a4e13 --- /dev/null +++ b/sample_project/app/migrations/0002_auto_20150824_0702.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='CustomWidgetComponent', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('widget_order', models.PositiveIntegerField(default=0, editable=False, db_index=True)), + ], + options={ + 'ordering': ['widget_order'], + 'verbose_name': 'Custom Widget Component', + 'verbose_name_plural': 'Custom Widget Components', + }, + ), + migrations.AlterField( + model_name='customwidget', + name='custom_order_field', + field=models.PositiveIntegerField(default=0, editable=False, db_index=True), + ), + migrations.AddField( + model_name='customwidgetcomponent', + name='custom_widget', + field=models.ForeignKey(to='app.CustomWidget'), + ), + ] diff --git a/sample_project/app/migrations/__init__.py b/sample_project/app/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sample_project/app/models.py b/sample_project/app/models.py index c4c44dd..4a472f0 100644 --- a/sample_project/app/models.py +++ b/sample_project/app/models.py @@ -202,3 +202,41 @@ class SortableNonInlineCategory(SimpleModel, SortableMixin): def __str__(self): return self.title + + +@python_2_unicode_compatible +class CustomWidget(SortableMixin, SimpleModel): + + # custom field for ordering + custom_order_field = models.PositiveIntegerField(default=0, db_index=True, + editable=False) + + order_field_name = 'custom_order_field' + + class Meta: + ordering = ['custom_order_field'] + verbose_name = 'Custom Widget' + verbose_name_plural = 'Custom Widgets' + + def __str__(self): + return self.title + + +@python_2_unicode_compatible +class CustomWidgetComponent(SortableMixin, SimpleModel): + + custom_widget = models.ForeignKey(CustomWidget) + + # custom field for ordering + widget_order = models.PositiveIntegerField(default=0, db_index=True, + editable=False) + + order_field_name = 'widget_order' + + class Meta: + ordering = ['widget_order'] + verbose_name = 'Custom Widget Component' + verbose_name_plural = 'Custom Widget Components' + + def __str__(self): + return self.title diff --git a/sample_project/database/test_project.sqlite b/sample_project/database/test_project.sqlite index af8ac5391519e0fd13c41aefc98c0da956caa8c9..7e4b0e7a7ee2c6f732b0b758cc2413ab725ea67b 100644 GIT binary patch delta 8576 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