From dd30e3967414df82b9ea014df67b32e989d306c8 Mon Sep 17 00:00:00 2001 From: Brandon Taylor Date: Sat, 6 Sep 2014 20:36:51 -0400 Subject: [PATCH] Added sample Project using Python 3.4 and Django 1.7. --- .gitignore | 1 + python3_sample_project/app/__init__.py | 0 python3_sample_project/app/admin.py | 67 ++++++++ python3_sample_project/app/fixtures/data.json | 52 ++++++ .../app/migrations/0001_initial.py | 146 ++++++++++++++++ .../app/migrations/__init__.py | 0 python3_sample_project/app/models.py | 121 ++++++++++++++ python3_sample_project/app/tests.py | 158 ++++++++++++++++++ .../database/python3-test-project.sqlite3 | Bin 0 -> 64512 bytes python3_sample_project/manage.py | 15 ++ .../python3_sample_project/__init__.py | 0 .../python3_sample_project/settings.py | 99 +++++++++++ .../python3_sample_project/urls.py | 10 ++ .../python3_sample_project/utils.py | 6 + .../python3_sample_project/wsgi.py | 14 ++ sample_project/app/admin.py | 1 + sample_project/database/test_project.sqlite | Bin 76800 -> 76800 bytes sample_project/requirements.txt | 3 +- 18 files changed, 691 insertions(+), 2 deletions(-) create mode 100644 python3_sample_project/app/__init__.py create mode 100644 python3_sample_project/app/admin.py create mode 100644 python3_sample_project/app/fixtures/data.json create mode 100644 python3_sample_project/app/migrations/0001_initial.py create mode 100644 python3_sample_project/app/migrations/__init__.py create mode 100644 python3_sample_project/app/models.py create mode 100644 python3_sample_project/app/tests.py create mode 100644 python3_sample_project/database/python3-test-project.sqlite3 create mode 100755 python3_sample_project/manage.py create mode 100644 python3_sample_project/python3_sample_project/__init__.py create mode 100644 python3_sample_project/python3_sample_project/settings.py create mode 100644 python3_sample_project/python3_sample_project/urls.py create mode 100644 python3_sample_project/python3_sample_project/utils.py create mode 100644 python3_sample_project/python3_sample_project/wsgi.py diff --git a/.gitignore b/.gitignore index be68f57..06ec6d9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ atlassian-* *.sublime-* .ropeproject .codeintel +__pycache__ diff --git a/python3_sample_project/app/__init__.py b/python3_sample_project/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3_sample_project/app/admin.py b/python3_sample_project/app/admin.py new file mode 100644 index 0000000..25783b3 --- /dev/null +++ b/python3_sample_project/app/admin.py @@ -0,0 +1,67 @@ +from django.contrib import admin + +from adminsortable.admin import (SortableAdmin, SortableTabularInline, + SortableStackedInline, SortableGenericStackedInline) +from adminsortable.utils import get_is_sortable +from app.models import (Category, Widget, Project, Credit, Note, GenericNote, + Component, Person) + + +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 + extra = 1 + + +class NoteInline(SortableStackedInline): + model = Note + extra = 0 + + +class GenericNoteInline(SortableGenericStackedInline): + model = GenericNote + extra = 0 + + +class ProjectAdmin(SortableAdmin): + inlines = [CreditInline, NoteInline, GenericNoteInline] + list_display = ['__str__', 'category'] + +admin.site.register(Project, ProjectAdmin) + + +class PersonAdmin(SortableAdmin): + list_display = ['__str__', 'is_board_member'] + +admin.site.register(Person, PersonAdmin) diff --git a/python3_sample_project/app/fixtures/data.json b/python3_sample_project/app/fixtures/data.json new file mode 100644 index 0000000..25f6d7d --- /dev/null +++ b/python3_sample_project/app/fixtures/data.json @@ -0,0 +1,52 @@ +[ +{ + "fields": { + "is_board_member": true, + "order": 1, + "first_name": "Brandon", + "last_name": "Taylor" + }, + "pk": 1, + "model": "app.person" +}, +{ + "fields": { + "is_board_member": true, + "order": 2, + "first_name": "Kerri", + "last_name": "Taylor" + }, + "pk": 2, + "model": "app.person" +}, +{ + "fields": { + "is_board_member": false, + "order": 3, + "first_name": "Sarah", + "last_name": "Taylor" + }, + "pk": 3, + "model": "app.person" +}, +{ + "fields": { + "is_board_member": false, + "order": 4, + "first_name": "Renna", + "last_name": "Taylor" + }, + "pk": 4, + "model": "app.person" +}, +{ + "fields": { + "is_board_member": false, + "order": 5, + "first_name": "Jake", + "last_name": "Taylor" + }, + "pk": 5, + "model": "app.person" +} +] diff --git a/python3_sample_project/app/migrations/0001_initial.py b/python3_sample_project/app/migrations/0001_initial.py new file mode 100644 index 0000000..ab0527a --- /dev/null +++ b/python3_sample_project/app/migrations/0001_initial.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import adminsortable.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('title', models.CharField(max_length=50)), + ], + options={ + 'ordering': ['order'], + 'verbose_name_plural': 'Categories', + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Component', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('title', models.CharField(max_length=50)), + ], + options={ + 'ordering': ['order'], + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Credit', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('first_name', models.CharField(max_length=30)), + ('last_name', models.CharField(max_length=30)), + ], + options={ + 'ordering': ['order'], + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='GenericNote', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('title', models.CharField(max_length=50)), + ('object_id', models.PositiveIntegerField(verbose_name='Content id')), + ('content_type', models.ForeignKey(related_name='generic_notes', verbose_name='Content type', to='contenttypes.ContentType')), + ], + options={ + 'ordering': ['order'], + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Note', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('text', models.CharField(max_length=100)), + ], + options={ + 'ordering': ['order'], + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Person', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('first_name', models.CharField(max_length=50)), + ('last_name', models.CharField(max_length=50)), + ('is_board_member', models.BooleanField(verbose_name='Board Member', default=False)), + ], + options={ + 'ordering': ['order'], + 'verbose_name_plural': 'People', + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Project', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('title', models.CharField(max_length=50)), + ('description', models.TextField()), + ('category', adminsortable.fields.SortableForeignKey(to='app.Category')), + ], + options={ + 'ordering': ['order'], + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Widget', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), + ('order', models.PositiveIntegerField(editable=False, default=1, db_index=True)), + ('title', models.CharField(max_length=50)), + ], + options={ + 'ordering': ['order'], + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='note', + name='project', + field=models.ForeignKey(to='app.Project'), + preserve_default=True, + ), + migrations.AddField( + model_name='credit', + name='project', + field=models.ForeignKey(to='app.Project'), + preserve_default=True, + ), + migrations.AddField( + model_name='component', + name='widget', + field=adminsortable.fields.SortableForeignKey(to='app.Widget'), + preserve_default=True, + ), + ] diff --git a/python3_sample_project/app/migrations/__init__.py b/python3_sample_project/app/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3_sample_project/app/models.py b/python3_sample_project/app/models.py new file mode 100644 index 0000000..9fe5a0b --- /dev/null +++ b/python3_sample_project/app/models.py @@ -0,0 +1,121 @@ +from django.contrib.contenttypes import generic +from django.contrib.contenttypes.models import ContentType +from django.db import models + +from adminsortable.fields import SortableForeignKey +from adminsortable.models import Sortable + + +class SimpleModel(models.Model): + class Meta: + abstract = True + + title = models.CharField(max_length=50) + + def __unicode__(self): + return self.title + + +# A model that is sortable +class Category(SimpleModel, Sortable): + class Meta(Sortable.Meta): + """ + Classes that inherit from Sortable must define an inner + Meta class that inherits from Sortable.Meta or ordering + won't work as expected + """ + verbose_name_plural = 'Categories' + + def __str__(self): + return self.title + + +# A model with an override of its queryset for admin +class Widget(SimpleModel, Sortable): + class Meta(Sortable.Meta): + pass + + def __str__(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 + + category = SortableForeignKey(Category) + description = models.TextField() + + +# Registered as a tabular inline on `Project` +class Credit(Sortable): + class Meta(Sortable.Meta): + pass + + project = models.ForeignKey(Project) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) + + def __str__(self): + return '{0} {1}'.format(self.first_name, self.last_name) + + +# Registered as a stacked inline on `Project` +class Note(Sortable): + class Meta(Sortable.Meta): + pass + + project = models.ForeignKey(Project) + text = models.CharField(max_length=100) + + def __str__(self): + return self.text + + +# A generic bound model +class GenericNote(SimpleModel, Sortable): + content_type = models.ForeignKey(ContentType, + verbose_name=u"Content type", related_name="generic_notes") + object_id = models.PositiveIntegerField(u"Content id") + content_object = generic.GenericForeignKey(ct_field='content_type', + fk_field='object_id') + + class Meta(Sortable.Meta): + pass + + def __str__(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 __str__(self): + return self.title + + +class Person(Sortable): + class Meta(Sortable.Meta): + verbose_name_plural = 'People' + + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + is_board_member = models.BooleanField('Board Member', default=False) + + # Sorting Filters allow you to set up sub-sets of objects that need + # to have independent sorting. They are listed in order, from left + # to right in the sorting change list. You can use any standard + # Django ORM filter method. + sorting_filters = ( + ('Board Members', {'is_board_member': True}), + ('Non-Board Members', {'is_board_member': False}), + ) + + def __str__(self): + return '{0} {1}'.format(self.first_name, self.last_name) diff --git a/python3_sample_project/app/tests.py b/python3_sample_project/app/tests.py new file mode 100644 index 0000000..66e1a4b --- /dev/null +++ b/python3_sample_project/app/tests.py @@ -0,0 +1,158 @@ +import http.client +import json + +from django.contrib.auth.models import User +from django.test import TestCase +from django.test.client import Client, RequestFactory + +from adminsortable.utils import get_is_sortable +from app.models import Category, Person + + +class SortableTestCase(TestCase): + fixtures = ['data.json'] + + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + self.user_raw_password = 'admin' + self.user = User.objects.create_user('admin', 'admin@admin.com', + self.user_raw_password) + self.user.is_staff = True + self.user.is_superuser = True + self.user.save() + + people = Person.objects.all() + self.first_person = people[0] + self.second_person = people[1] + + def create_category(self, title='Category 1'): + category = Category.objects.create(title=title) + return category + + def test_new_user_is_authenticated(self): + self.assertEqual(self.user.is_authenticated(), True, + 'User is not authenticated') + + def test_new_user_is_staff(self): + self.assertEqual(self.user.is_staff, True, 'User is not staff') + + def test_is_not_sortable(self): + """ + A model should only become sortable if it has more than + record to sort. + """ + self.create_category() + self.assertFalse(get_is_sortable(Category.objects.all()), + 'Category only has one record. It should not be sortable.') + + def test_is_sortable(self): + self.create_category() + self.create_category(title='Category 2') + self.assertTrue(get_is_sortable(Category.objects.all()), + 'Category has more than one record. It should be sortable.') + + def test_save_order_incremented(self): + category1 = self.create_category() + self.assertEqual(category1.order, 1, 'Category 1 order should be 1.') + + category2 = self.create_category(title='Category 2') + self.assertEqual(category2.order, 2, 'Category 2 order should be 2.') + + def test_adminsortable_change_list_view(self): + self.client.login(username=self.user.username, + password=self.user_raw_password) + response = self.client.get('/admin/app/category/sort/') + self.assertEquals(response.status_code, http.client.OK, + 'Unable to reach sort view.') + + def make_test_categories(self): + category1 = self.create_category() + category2 = self.create_category(title='Category 2') + category3 = self.create_category(title='Category 3') + return category1, category2, category3 + + def get_sorting_url(self): + return '/admin/app/category/sorting/do-sorting/{0}/'.format( + Category.model_type_id()) + + def get_category_indexes(self, *categories): + return {'indexes': ','.join([str(c.id) for c in categories])} + + def test_adminsortable_changelist_templates(self): + logged_in = self.client.login(username=self.user.username, + password=self.user_raw_password) + self.assertTrue(logged_in, 'User is not logged in') + + response = self.client.get('/admin/app/category/sort/') + self.assertEqual(response.status_code, http.client.OK, + 'Admin sort request failed.') + + #assert adminsortable change list templates are used + template_names = [t.name for t in response.templates] + self.assertTrue('adminsortable/change_list.html' in template_names, + 'adminsortable/change_list.html was not rendered') + + def test_adminsortable_change_list_sorting_fails_if_not_ajax(self): + logged_in = self.client.login(username=self.user.username, + password=self.user_raw_password) + self.assertTrue(logged_in, 'User is not logged in') + + category1, category2, category3 = self.make_test_categories() + #make a normal POST + response = self.client.post(self.get_sorting_url(), + data=self.get_category_indexes(category1, category2, category3)) + content = json.loads(response.content.decode(encoding='UTF-8'), + 'latin-1') + self.assertFalse(content.get('objects_sorted'), + 'Objects should not have been sorted. An ajax post is required.') + + def test_adminsortable_change_list_sorting_successful(self): + logged_in = self.client.login(username=self.user.username, + password=self.user_raw_password) + self.assertTrue(logged_in, 'User is not logged in') + + #make categories + category1, category2, category3 = self.make_test_categories() + + #make an Ajax POST + response = self.client.post(self.get_sorting_url(), + data=self.get_category_indexes(category3, category2, category1), + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + content = json.loads(response.content.decode(encoding='UTF-8'), + 'latin-1') + self.assertTrue(content.get('objects_sorted'), + 'Objects should have been sorted.') + + #assert order is correct + categories = Category.objects.all() + cat1 = categories[0] + cat2 = categories[1] + cat3 = categories[2] + + self.assertEqual(cat1.order, 1, + 'First category returned should have order == 1') + self.assertEqual(cat1.pk, 3, + 'Category ID 3 should have been first in queryset') + + self.assertEqual(cat2.order, 2, + 'Second category returned should have order == 2') + self.assertEqual(cat2.pk, 2, + 'Category ID 2 should have been second in queryset') + + self.assertEqual(cat3.order, 3, + 'Third category returned should have order == 3') + self.assertEqual(cat3.pk, 1, + 'Category ID 1 should have been third in queryset') + + def test_get_next(self): + result = self.first_person.get_next() + + self.assertEqual(self.second_person, result, 'Next person should ' + 'be "{}"'.format(self.second_person)) + + def test_get_previous(self): + result = self.second_person.get_previous() + + self.assertEqual(self.first_person, result, 'Previous person should ' + 'be "{}"'.format(self.first_person)) diff --git a/python3_sample_project/database/python3-test-project.sqlite3 b/python3_sample_project/database/python3-test-project.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..76b853c51bbcb769c2028d06b594c08f5738eb54 GIT binary patch literal 64512 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 literal 0 HcmV?d00001 diff --git a/python3_sample_project/manage.py b/python3_sample_project/manage.py new file mode 100755 index 0000000..08821aa --- /dev/null +++ b/python3_sample_project/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os +import sys + +# Adds the adminsortable package from the cloned repository instead of +# site_packages +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", + "python3_sample_project.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/python3_sample_project/python3_sample_project/__init__.py b/python3_sample_project/python3_sample_project/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3_sample_project/python3_sample_project/settings.py b/python3_sample_project/python3_sample_project/settings.py new file mode 100644 index 0000000..5d729fe --- /dev/null +++ b/python3_sample_project/python3_sample_project/settings.py @@ -0,0 +1,99 @@ +""" +Django settings for python3_sample_project project. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.7/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +from .utils import map_path + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'k^uy@(9tieoj3d%o=09ph$b&gu+5q@9h$f(6l7@h2ak*0@y9%w' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +TEMPLATE_DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + 'adminsortable', + 'app', +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = 'python3_sample_project.urls' + +WSGI_APPLICATION = 'python3_sample_project.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.7/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': map_path('database/python3-test-project.sqlite3'), + }, + 'test': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': map_path('database/test-python3-test-project.sqlite3'), + } +} + +# Internationalization +# https://docs.djangoproject.com/en/1.7/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.7/howto/static-files/ + +STATIC_URL = '/static/' + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +) + +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +) diff --git a/python3_sample_project/python3_sample_project/urls.py b/python3_sample_project/python3_sample_project/urls.py new file mode 100644 index 0000000..c4b2ed2 --- /dev/null +++ b/python3_sample_project/python3_sample_project/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import patterns, include, url +from django.contrib import admin + +urlpatterns = patterns('', + # Examples: + # url(r'^$', 'python3_sample_project.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), + + url(r'^admin/', include(admin.site.urls)), +) diff --git a/python3_sample_project/python3_sample_project/utils.py b/python3_sample_project/python3_sample_project/utils.py new file mode 100644 index 0000000..4178ad9 --- /dev/null +++ b/python3_sample_project/python3_sample_project/utils.py @@ -0,0 +1,6 @@ +import os + + +def map_path(directory_name): + return os.path.join(os.path.dirname(__file__), + '../' + directory_name).replace('\\', '/') diff --git a/python3_sample_project/python3_sample_project/wsgi.py b/python3_sample_project/python3_sample_project/wsgi.py new file mode 100644 index 0000000..1256fa7 --- /dev/null +++ b/python3_sample_project/python3_sample_project/wsgi.py @@ -0,0 +1,14 @@ +""" +WSGI config for python3_sample_project project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ +""" + +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "python3_sample_project.settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() diff --git a/sample_project/app/admin.py b/sample_project/app/admin.py index bf2a5fb..304be18 100644 --- a/sample_project/app/admin.py +++ b/sample_project/app/admin.py @@ -41,6 +41,7 @@ admin.site.register(Widget, WidgetAdmin) class CreditInline(SortableTabularInline): model = Credit + extra = 1 class NoteInline(SortableStackedInline): diff --git a/sample_project/database/test_project.sqlite b/sample_project/database/test_project.sqlite index 98505cfdc228b6d5243b78dc9c0757822c6f89f5..5dd00e7a42b8d6c0392a4b4b0423a506b689649c 100644 GIT binary patch delta 660 zcmZ9I&ubGw6vt=gJDZXpVq;>(R_Z2LL$f4qk~KCtX?TUdK6ote`}uy~%q(s5rEUIf zgof5GOwmyN?yJYp5ETPYavWC>ZTk5)=HYNt&2CX)tZYDI$6{bL4uu^zjnyyAr+`wo z=JaUO`}BzW>IA3})bI)WGUE|MO+>_w7!-9eF80On8DQOo*Z7K`Sa9m0c4zeaS=*K&Vx->^7DoA{7inaRIW6hv!L%to~%Xi z2QB=P8}}euZ@g}4<@N?H>T8+d^t zRQ7|dusiG`ZPO`oApHFM*o@{TH{A4ejNVG>2_vRwVtQIlrn0G2)=0+_>4{`2VXXye z=vwbR)b4|XgCtVX5J4dsK?N1mz3;~I1dDD8c!vY%h9>S;;hfoy^erMk@S2# zlA4b%$elun7?Wp(-ag0B&;Ecxqp6r{a7-8CwdXeiCmMKD8}A?+ z2d%b%%@vA?;vtFl2WFr`_(lay+~Nt>xKpzynDBse5?XCrt7!or%)@kTnOfByDm+XR z(V|uvP(SmEcRbhslMI<<{CLT$>hm37N%HG23bLCPNv!NFYR2%F+}C Oc~fDk{J7cAea0V~CTPL{ diff --git a/sample_project/requirements.txt b/sample_project/requirements.txt index 0a26803..d3e4ba5 100644 --- a/sample_project/requirements.txt +++ b/sample_project/requirements.txt @@ -1,2 +1 @@ -django==1.6.6 -south==1.0 +django