├── .gitignore ├── AUTHORS ├── DESCRIPTION ├── LICENSE ├── MANIFEST.in ├── README.rst ├── appname ├── __init__.py ├── admin.py ├── fixtures │ └── test_data.json ├── models.py ├── templates │ └── appname │ │ └── example_list.html ├── tests │ ├── __init__.py │ ├── models.py │ ├── runtests.py │ ├── tests.py │ └── urls.py ├── urls.py └── views.py ├── bin └── init.sh ├── lib └── README.rst └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | build/ 3 | dist/ 4 | *egg-info/ 5 | 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Current or previous core committers 2 | 3 | * TODO: Add core committers 4 | 5 | Contributors (in alphabetical order) 6 | 7 | * Your name could stand here :) 8 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | TODO: Add long description 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include appname * 2 | include README.rst DESCRIPTION 3 | exclude *.orig *.pyc *.wpr 4 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Django Reusable App Boilerplate 2 | =============================== 3 | 4 | If you work with Django every day you will want to build reusable apps. This repository should work as a boilerplate for reusable Django apps. 5 | 6 | **Features:** 7 | 8 | * It is ready for test driven development (TDD). Add your first test to tests.py before you implement anything! 9 | * It is ready to be distributed via PyPi 10 | 11 | We are still far from being experts in producing reusable apps. This repository is more or less what we have learned from some inspiring blog posts and from looking at other awesome repositories out there. The whole process of submitting an app based on this boilerplate to PyPi has never been tested (but will be tested soon). Suggestions for enhancements are much appreciated! 12 | 13 | You can find another promising try on the same issue here: 14 | 15 | * `django-packagemaker `_ 16 | 17 | 18 | How to use 19 | ========== 20 | 21 | :: 22 | 23 | git clone git://github.com/bitmazk/django-reusable-app-boilerplate yourappname 24 | cd yourappname 25 | ./bin/init.sh 26 | ./yourappname/tests/runtests.py 27 | 28 | The ``init.sh`` a script will ask you for some variables like your desired app-name and other information like keywords, app URL, app author and author email. Your inputs will be used to rename some folders and replace module names and imports in the boilerplate files provided. It will also be used to prepare your ``setup.py`` for easy distribution of your app via PyPi. 29 | -------------------------------------------------------------------------------- /appname/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | VERSION = (0, 0, 1, 'alpha') 3 | if VERSION[-1] != "final": # pragma: no cover 4 | __version__ = '.'.join(map(str, VERSION)) 5 | else: # pragma: no cover 6 | __version__ = '.'.join(map(str, VERSION[:-1])) 7 | -------------------------------------------------------------------------------- /appname/admin.py: -------------------------------------------------------------------------------- 1 | """Admin classes for appname application.""" 2 | 3 | from django.contrib import admin 4 | 5 | from appname.models import Example 6 | 7 | 8 | class ExampleAdmin(admin.ModelAdmin): 9 | """Admin class for Example model class.""" 10 | pass 11 | 12 | 13 | admin.site.register(Example, ExampleAdmin) 14 | -------------------------------------------------------------------------------- /appname/fixtures/test_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pk": 1, 4 | "model": "appname.example", 5 | "fields": { 6 | "text": "Lorem ipsum..." 7 | } 8 | }, 9 | { 10 | "pk": 2, 11 | "model": "appname.example", 12 | "fields": { 13 | "text": "Foo bar..." 14 | } 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /appname/models.py: -------------------------------------------------------------------------------- 1 | """Models for appname application.""" 2 | 3 | from django.db import models 4 | 5 | 6 | class Example(models.Model): 7 | """Example model class.""" 8 | text = models.TextField(blank=True, null=True) 9 | -------------------------------------------------------------------------------- /appname/templates/appname/example_list.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlabstudio/django-reusable-app-boilerplate/4c706e94cca2ad73d788b282f2232d9a2c8e006b/appname/templates/appname/example_list.html -------------------------------------------------------------------------------- /appname/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlabstudio/django-reusable-app-boilerplate/4c706e94cca2ad73d788b282f2232d9a2c8e006b/appname/tests/__init__.py -------------------------------------------------------------------------------- /appname/tests/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlabstudio/django-reusable-app-boilerplate/4c706e94cca2ad73d788b282f2232d9a2c8e006b/appname/tests/models.py -------------------------------------------------------------------------------- /appname/tests/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | from django.conf import settings 6 | 7 | 8 | if not settings.configured: 9 | settings.configure( 10 | DATABASE_ENGINE='sqlite3', 11 | ROOT_URLCONF='appname.tests.urls', 12 | INSTALLED_APPS=[ 13 | 'appname', 14 | 'appname.tests', 15 | ] 16 | ) 17 | 18 | 19 | from django.test.simple import run_tests 20 | 21 | 22 | def runtests(*test_args): 23 | if not test_args: 24 | test_args = ['tests'] 25 | parent = os.path.join( 26 | os.path.dirname(os.path.abspath(__file__)), 27 | "..", 28 | "..", 29 | ) 30 | sys.path.insert(0, parent) 31 | failures = run_tests(test_args, verbosity=1, interactive=True) 32 | sys.exit(failures) 33 | 34 | 35 | if __name__ == '__main__': 36 | runtests(*sys.argv[1:]) 37 | -------------------------------------------------------------------------------- /appname/tests/tests.py: -------------------------------------------------------------------------------- 1 | """Tests for appname application.""" 2 | 3 | from unittest import TestCase 4 | from django.test import TestCase as DjangoTestCase 5 | 6 | 7 | class TestSuiteTestCase(TestCase): 8 | """General test to make sure that the setup works.""" 9 | def test_test_suite_can_be_run(self): 10 | self.assertTrue(True) 11 | 12 | 13 | class ExampleTestCase(DjangoTestCase): 14 | """Tests for Example model class.""" 15 | fixtures = ['test_data'] 16 | urls = 'appname.tests.urls' 17 | 18 | def test_example_view_is_callable(self): 19 | resp = self.client.get('/example/') 20 | self.assertEqual(resp.status_code, 200) 21 | -------------------------------------------------------------------------------- /appname/tests/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | 4 | urlpatterns = patterns('', 5 | url(r'^example/', include('appname.urls')), 6 | ) 7 | -------------------------------------------------------------------------------- /appname/urls.py: -------------------------------------------------------------------------------- 1 | """URLs for appname application.""" 2 | 3 | from django.conf.urls.defaults import * 4 | 5 | 6 | urlpatterns = patterns('appname.views', 7 | url(r'^$', view='index', name='appname_index'), 8 | ) 9 | -------------------------------------------------------------------------------- /appname/views.py: -------------------------------------------------------------------------------- 1 | """Views for appname application.""" 2 | 3 | from django.http import HttpResponse, Http404 4 | from django.shortcuts import get_object_or_404 5 | from django.views.generic.list_detail import object_list 6 | 7 | 8 | from appname.models import Example 9 | 10 | 11 | def index(request, template_name='appname/example_list.html'): 12 | """Index view.""" 13 | qs = Example.objects.all() 14 | 15 | try: 16 | page = int(request.GET.get('page', 0)) 17 | except ValueError: 18 | raise Http404 19 | 20 | return object_list( 21 | request, 22 | queryset=qs, 23 | template_object_name='example', 24 | paginate_by=10, 25 | page=page, 26 | ) 27 | -------------------------------------------------------------------------------- /bin/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Name of your reusable app:" 3 | read APPNAME 4 | echo "Keywords for your app:" 5 | read KEYWORDS 6 | echo "Author of your app:" 7 | read AUTHOR 8 | echo "Author email of your app:" 9 | read AUTHOREMAIL 10 | echo "URL for your app:" 11 | read URL 12 | 13 | echo "Deleting .git folder" 14 | rm -rf .git 15 | 16 | echo "Replacing README.rst" 17 | rm README.rst 18 | mv lib/README.rst . 19 | rm -rf lib 20 | 21 | echo "Replacing strings in files..." 22 | sed -i "s/the_keywords/$KEYWORDS/g" setup.py 23 | sed -i "s/the_author/$AUTHOR/g" setup.py 24 | sed -i "s/the_email/$AUTHOREMAIL/g" setup.py 25 | sed -i "s@the_url@$URL@g" setup.py 26 | find . -type f -exec sed -i "s/appname/$APPNAME/g" {} + 27 | 28 | echo "Renaming folders..." 29 | mv appname/templates/appname/ appname/templates/$APPNAME 30 | mv appname $APPNAME 31 | 32 | echo "Deleting bin folder..." 33 | rm -rf bin 34 | 35 | echo "Initialize new git repository..." 36 | git init 37 | git add . 38 | git commit -am "Initial commit" 39 | 40 | echo "Done! Please edit AUTHORS, DESCRIPTION and README.rst now." 41 | -------------------------------------------------------------------------------- /lib/README.rst: -------------------------------------------------------------------------------- 1 | TODO: Add app name 2 | ================== 3 | 4 | TODO: Add project readme. 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | import appname 4 | 5 | 6 | def read(fname): 7 | try: 8 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 9 | except IOError: 10 | return '' 11 | 12 | 13 | setup( 14 | name="appname", 15 | version=appname.__version__, 16 | description=read('DESCRIPTION'), 17 | long_description=read('README.rst'), 18 | keywords='the_keywords', 19 | packages=find_packages(), 20 | author='the_author', 21 | author_email='the_email', 22 | url="the_url", 23 | include_package_data=True, 24 | test_suite='appname.tests.runtests.runtests', 25 | ) 26 | --------------------------------------------------------------------------------