diff --git a/.gitignore b/.gitignore index b2fe1df..1c97fe3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,64 +1,2 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* .cache -nosetests.xml -coverage.xml -*,cover - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# IDE specifics -.idea/ -*.swp - -# Database specifics -*.sqlite \ No newline at end of file +__pycache__/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..94f3ed7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: python + +python: 3.5 +env: + - TOXENV=py27 + - TOXENV=py33 + - TOXENV=py34 + - TOXENV=py35 + +install: + - pip install -U tox + +script: + - tox diff --git a/README.md b/README.md index 04a291e..e66eeb3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -# django-api-template +# django-api-template +[![Build Status](https://travis-ci.org/harnash/django_api_template.svg?branch=master)](https://travis-ci.org/harnash/django_api_template) + Django project template for building RESTful API services diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..3a68f9f --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "apps_dir": "apps", + "project_name": "my_project", + "project_dir": "{{cookiecutter.project_name|replace(' ', '_')}}", + "secret_key": "FOR DEV ONLY - CHANGE ME", + "database_type": ["PostgreSQL", "MySQL", "SQLite", "Other"], + "database_url": "{{cookiecutter.database_type|lower}}://path_to_database" +} \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..ad16166 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +testpaths = tests/ \ No newline at end of file diff --git a/requirements/_base.txt b/requirements/_base.txt deleted file mode 100644 index 9f94d68..0000000 --- a/requirements/_base.txt +++ /dev/null @@ -1,43 +0,0 @@ -# Base requirements file. -# Place items here that should be installed in ALL environments. - -django==1.8 -djangorestframework==3.1.1 - -## Needed by the settings base module. Do not remove. -Unipath==1.1 -dj-database-url==0.3.0 - -##################################################### -# -# Below are some commonly used django apps, included -# here for convenience. -# Be sure to add version numbers here!!!! -# -##################################################### - -# Convenient utilities for Django Models -# https://github.com/carljm/django-model-utils -# django-model-utils - -# PostgreSQL Database Adapter -# psycopg2 - -# MySQL Database Adapter -# django-cymysql - -##################################################### -# -# Django REST Framework Addons -# Some usefull thir party addons to DRF -# -##################################################### - -# https://github.com/juanriaza/django-rest-framework-msgpack -# djangorestframework-msgpack - -# https://github.com/gizmag/drf-ujson-renderer -# drf_ujson - -# https://github.com/marcgibbons/django-rest-swagger -# django-rest-swagger \ No newline at end of file diff --git a/requirements/local.txt b/requirements/local.txt deleted file mode 100644 index fedeb02..0000000 --- a/requirements/local.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Local requirements file. -# Place items here that should ONLY be installed in DEVELOPMENT environments. - -# include the base requirements file --r _base.txt - -django-debug-toolbar -django-extensions - -# For easy deployments -# http://docs.fabfile.org/en/latest/ -# Fabric - -# For building documentation -# http://sphinx-doc.org/ -Sphinx - -# For running tests -coverage \ No newline at end of file diff --git a/tests/test_sample_projects.py b/tests/test_sample_projects.py new file mode 100644 index 0000000..4c874ef --- /dev/null +++ b/tests/test_sample_projects.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from contextlib import contextmanager +from cookiecutter.utils import rmtree + + +@contextmanager +def temporary_project(cookies, *args, **kwargs): + """ + Delete the temporal directory that is created when executing the tests + :param cookies: pytest_cookies.Cookies + """ + result = cookies.bake(*args, **kwargs) + try: + yield result + finally: + rmtree(str(result.project)) + +def test_envrc(cookies): + """ + Test if the .envrc file was created successfully + """ + + extra_context = {'project_name': 'environ'} + + with temporary_project(cookies, extra_context=extra_context) as result: + envrc_file = result.project.join('.envrc') + lines = [x.strip() for x in envrc_file.readlines(cr=False)] + assert 'export ENVIRON_SECRET_KEY=FOR DEV ONLY - CHANGE ME' in lines + assert 'export ENVIRON_DATABASE_URL=postgresql://path_to_database' in lines \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..1d51c08 --- /dev/null +++ b/tox.ini @@ -0,0 +1,20 @@ +[tox] +envlist = py27, py33, py34, py35, pypy +skipsdist = true + +[testenv] +whitelist_externals = bash +deps = + Django>=1.10 + pip + cookiecutter + pytest-cookies + pytest + tox + pytest-cov + watchdog + sh + flake8 + +commands = + py.test \ No newline at end of file diff --git a/{{cookiecutter.project_dir}}/.gitignore b/{{cookiecutter.project_dir}}/.gitignore new file mode 100644 index 0000000..f49a3c2 --- /dev/null +++ b/{{cookiecutter.project_dir}}/.gitignore @@ -0,0 +1,65 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +.venv/ + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IDE specifics +.idea/ +*.swp + +# Database specifics +*.sqlite diff --git a/{{cookiecutter.project_dir}}/Pipfile b/{{cookiecutter.project_dir}}/Pipfile new file mode 100644 index 0000000..2a33695 --- /dev/null +++ b/{{cookiecutter.project_dir}}/Pipfile @@ -0,0 +1,20 @@ +[[source]] +url = "https://pypi.org/" +verify_ssl = true + +[dev-packages] +django-extensions = "*" +Sphinx = "*" +django-debug-toolbar = "*" +Werkzeug = "*" + +[packages] +Unipath = "*" +djangorestframework = ">=3.5" +dj-database-url = "*" +django = ">=1.10" +{% if cookiecutter.database_type == "MySQL" %} +mysqlclient = ">=1.3" +{% elif cookiecutter.database_type == "PostgreSQL" %} +psycopg2 = ">=2.7" +{% endif %} diff --git a/{{cookiecutter.project_dir}}/Pipfile.lock b/{{cookiecutter.project_dir}}/Pipfile.lock new file mode 100644 index 0000000..628edcd --- /dev/null +++ b/{{cookiecutter.project_dir}}/Pipfile.lock @@ -0,0 +1,38 @@ +{ + "default": { + "Unipath": "==1.1", + "djangorestframework": "==3.5.4", + "django": ">=1.10", + "Django": "==1.10.6", + "dj-database-url": "==0.4.2" + }, + "develop": { + "sqlparse": "==0.2.3", + "Sphinx": "==1.5.3", + "django-debug-toolbar": "==1.6", + "pytz": "==2016.10", + "docutils": "==0.13.1", + "snowballstemmer": "==1.2.1", + "Babel": "==2.3.4", + "alabaster": "==0.7.10", + "six": "==1.10.0", + "Django": "==1.10.6", + "django-extensions": "==1.7.7", + "Pygments": "==2.2.0", + "Jinja2": "==2.9.5", + "Werkzeug": "==0.11.15", + "MarkupSafe": "==0.23", + "requests": "==2.13.0", + "imagesize": "==0.7.1" + }, + "_meta": { + "sources": [ + { + "url": "https://pypi.org/", + "verify_ssl": true + } + ], + "requires": {}, + "Pipfile-sha256": "c0db6c138ffd72f9a97b6d74b6ef4eda26b64b4020dde59af31b23fcdb8e5225" + } +} \ No newline at end of file diff --git a/static/media/.gitdirectory b/{{cookiecutter.project_dir}}/static/media/.gitdirectory similarity index 100% rename from static/media/.gitdirectory rename to {{cookiecutter.project_dir}}/static/media/.gitdirectory diff --git a/templates/.gitdirectory b/{{cookiecutter.project_dir}}/templates/.gitdirectory similarity index 100% rename from templates/.gitdirectory rename to {{cookiecutter.project_dir}}/templates/.gitdirectory diff --git a/apps/project_name/__init__.py b/{{cookiecutter.project_dir}}/tests/__init__.py similarity index 100% rename from apps/project_name/__init__.py rename to {{cookiecutter.project_dir}}/tests/__init__.py diff --git a/apps/manage.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/manage.py similarity index 64% rename from apps/manage.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/manage.py index 391dd88..fd402d4 100644 --- a/apps/manage.py +++ b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/manage.py @@ -3,7 +3,7 @@ import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{cookiecutter.project_name}}.settings.local") from django.core.management import execute_from_command_line diff --git a/apps/project_name/settings/__init__.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/__init__.py similarity index 100% rename from apps/project_name/settings/__init__.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/__init__.py diff --git a/tests/__init__.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/__init__.py similarity index 100% rename from tests/__init__.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/__init__.py diff --git a/apps/project_name/settings/base.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/base.py similarity index 94% rename from apps/project_name/settings/base.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/base.py index 3d2317a..6de899c 100644 --- a/apps/project_name/settings/base.py +++ b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/base.py @@ -27,7 +27,7 @@ def get_env_var(varname, default=None): MANAGERS = ADMINS DATABASES = { - 'default': dj_database_url.parse(get_env_var('{{ project_name|upper }}_DATABASE_URL')) + 'default': dj_database_url.parse(get_env_var('{{cookiecutter.project_name|upper}}_DATABASE_URL')) } # Local time zone for this installation. Choices can be found here: @@ -74,7 +74,7 @@ def get_env_var(varname, default=None): STATICFILES_DIRS = () # Make this unique, and don't share it with anybody. -SECRET_KEY = get_env_var('{{ project_name|upper }}_SECRET_KEY') +SECRET_KEY = get_env_var('{{cookiecutter.project_name|upper}}_SECRET_KEY') MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', @@ -87,10 +87,10 @@ def get_env_var(varname, default=None): 'django.middleware.security.SecurityMiddleware', ) -ROOT_URLCONF = '{{ project_name }}.urls' +ROOT_URLCONF = '{{cookiecutter.project_name}}.urls' # Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = '{{ project_name }}.wsgi.application' +WSGI_APPLICATION = '{{cookiecutter.project_name}}.wsgi.application' TEMPLATES = [ { diff --git a/apps/project_name/settings/local.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/local.py similarity index 82% rename from apps/project_name/settings/local.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/local.py index ed7a667..070fc12 100644 --- a/apps/project_name/settings/local.py +++ b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/settings/local.py @@ -3,7 +3,7 @@ from .base import * -DEBUG = TEMPLATE_DEBUG = True +DEBUG = True # Send emails to the console EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' @@ -32,8 +32,10 @@ def show_toolbar(request): DEBUG_TOOLBAR_CONFIG = { - 'SHOW_TOOLBAR_CALLBACK': "{{ project_name }}.settings.local.show_toolbar", + 'SHOW_TOOLBAR_CALLBACK': "{{cookiecutter.project_name}}.settings.local.show_toolbar", } +DEBUG_TOOLBAR_PATCH_SETTINGS = False + INSTALLED_APPS += DEBUG_APPS diff --git a/apps/project_name/urls.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/urls.py similarity index 61% rename from apps/project_name/urls.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/urls.py index df17d83..5ae560b 100644 --- a/apps/project_name/urls.py +++ b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/urls.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.conf.urls import include, url from django.contrib import admin @@ -8,3 +9,9 @@ url(r'^admin/', include(admin.site.urls)), ] + +if settings.DEBUG: + import debug_toolbar + urlpatterns += [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] diff --git a/apps/project_name/wsgi.py b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/wsgi.py similarity index 78% rename from apps/project_name/wsgi.py rename to {{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/wsgi.py index f817652..24e383e 100644 --- a/apps/project_name/wsgi.py +++ b/{{cookiecutter.project_dir}}/{{cookiecutter.apps_dir}}/{{cookiecutter.project_name}}/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{cookiecutter.project_name}}.settings") application = get_wsgi_application()