├── .gitignore ├── Dockerfile ├── README.md ├── manage.py ├── project_name ├── models.py ├── settings │ ├── __init__.py │ ├── base.py │ ├── local.py │ └── production.py ├── tests │ └── __init__.py ├── urls.py └── wsgi.py ├── pytest.ini ├── requirements ├── base.txt ├── local.txt ├── production.txt └── test.txt ├── run.py └── v2 ├── __init__.py └── tests ├── __init__.py └── conftest.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Add any directories, files, or patterns you don't want to be tracked by version control 2 | venv/ 3 | .idea/ 4 | *.pyc 5 | .DS_Store 6 | app/.DS_Store 7 | venv* 8 | .bin 9 | .vscode 10 | *.xlsx 11 | startup.sh 12 | *client_secret.json 13 | *.sqlite* 14 | microsetup -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # FROM revolutionsystems/python:3.6.3-wee-optimized-lto as python-base 2 | FROM python:3.6.4 3 | ENV PYTHONUNBUFFERED 1 4 | # RUN apt-get update && apt-get install -y git build-essential 5 | RUN pip install -U pip 6 | 7 | COPY requirements /requirements 8 | 9 | RUN pip install -r /requirements/production.txt 10 | RUN pip install -e git+https://gitlab+deploy-token-60342:Xs78xdAhrkn3pCucL2uP@gitlab.com/careerlyft-team/careerlyft-shared.git#egg=cv_utils 11 | 12 | COPY . /{{project_name}} 13 | 14 | RUN find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf 15 | 16 | EXPOSE 5000 17 | 18 | WORKDIR /{{project_name}} 19 | ENV DJANGO_SETTINGS_MODULE {{project_name}}.settings.production 20 | 21 | CMD gunicorn -k uvicorn.workers.UvicornWorker -b 0.0.0.0:5000 run:app --access-logfile - -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django micro setup # 2 | 3 | 4 | ### What is this repository for? ### 5 | 6 | This is a sample template to use when scaffolding a django project to be used as a microservice. 7 | 8 | It disables a lot of the default settings provided by django by default and provides multiple settings to choose between 9 | 10 | 11 | ### Configuration 12 | The bare minimum dependency to get the app to production is what is introduced. 13 | to install, run `pip install -r requirements/local.txt` 14 | 15 | ``` 16 | $ mkdir project_location 17 | $ python -m venv venv 18 | $ source venv/Scripts/activate # on linux/mac venv/bin/activate 19 | $ pip install -r requirements/local.txt 20 | $ django-admin startproject --template=https://github.com/gbozee/django-micro/archive/master.zip --name=Dockerfile 21 | 22 | ``` 23 | 24 | ### Database configuration 25 | The project makes use of environment variables which is a good way to switch configuration at runtime. 26 | The following are the variable supported 27 | 28 | **DATABASE_URL**: a url connection string of the database 29 | 30 | **DJANGO_SETTINGS_MODULE**: settings module to load the django app in *default is .settings.local* 31 | 32 | ### Running Tests 33 | To run tests, `python manage.py test ` 34 | 35 | ### Preparing for deployments 36 | There is a dockerfile created by default to help deploy the app as a docker-container. 37 | To build the docker container run the following command 38 | `docker build -t= .` 39 | 40 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", 7 | "{{project_name }}.settings.local") 8 | try: 9 | from django.core.management import execute_from_command_line 10 | except ImportError as exc: 11 | raise ImportError( 12 | "Couldn't import Django. Are you sure it's installed and " 13 | "available on your PYTHONPATH environment variable? Did you " 14 | "forget to activate a virtual environment?" 15 | ) from exc 16 | execute_from_command_line(sys.argv) 17 | -------------------------------------------------------------------------------- /project_name/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbozee/django-micro/64ffdb92e494b3ccd3e40e8f568e9f70d2651d18/project_name/models.py -------------------------------------------------------------------------------- /project_name/settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbozee/django-micro/64ffdb92e494b3ccd3e40e8f568e9f70d2651d18/project_name/settings/__init__.py -------------------------------------------------------------------------------- /project_name/settings/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_app project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.0.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | import environ 15 | env = environ.Env(DEBUG=(bool, False),) # set default values and casting 16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = 'a8m7&irp9qcdn=8-_*ag)qu@+k8o!_)dn90esu(4e%jp-bz!*s' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = [] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | # 'django.contrib.admin', 36 | # 'django.contrib.auth', 37 | # 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | # 'django.contrib.messages', 40 | # 'django.contrib.staticfiles', 41 | '{{project_name}}', 42 | ] 43 | 44 | MIDDLEWARE = [ 45 | 'corsheaders.middleware.CorsMiddleware', 46 | # 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | # 'django.middleware.common.CommonMiddleware', 49 | # 'django.middleware.csrf.CsrfViewMiddleware', 50 | # 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | # 'django.contrib.messages.middleware.MessageMiddleware', 52 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 53 | ] 54 | 55 | ROOT_URLCONF = '{{project_name}}.urls' 56 | CORS_ORIGIN_ALLOW_ALL = True 57 | 58 | 59 | WSGI_APPLICATION = '{{project_name}}.wsgi.application' 60 | 61 | 62 | # Database 63 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 64 | 65 | DATABASES = { 66 | # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ 67 | 'default': env.db('DATABASE_URL', default=''), 68 | # 'replica': env.db('REPLICA_DATABASE_URL', default='postgres://tuteria:punnisher@127.0.0.1:5435/tuteria') 69 | } 70 | DATABASES['default']['ATOMIC_REQUESTS'] = True 71 | 72 | 73 | # Internationalization 74 | # https://docs.djangoproject.com/en/2.0/topics/i18n/ 75 | 76 | LANGUAGE_CODE = 'en-us' 77 | 78 | TIME_ZONE = 'UTC' 79 | 80 | USE_I18N = True 81 | 82 | USE_L10N = True 83 | 84 | USE_TZ = True 85 | 86 | 87 | # Static files (CSS, JavaScript, Images) 88 | # https://docs.djangoproject.com/en/2.0/howto/static-files/ 89 | 90 | STATIC_URL = '/static/' -------------------------------------------------------------------------------- /project_name/settings/local.py: -------------------------------------------------------------------------------- 1 | from .base import * 2 | 3 | INSTALLED_APPS = INSTALLED_APPS + [ 4 | 'django_extensions', # extensions for django 5 | ] 6 | -------------------------------------------------------------------------------- /project_name/settings/production.py: -------------------------------------------------------------------------------- 1 | from .base import * 2 | 3 | DEBUG = False 4 | 5 | ALLOWED_HOSTS = ['*'] 6 | 7 | LOGGING = { 8 | 'version': 1, 9 | 'disable_existing_loggers': False, 10 | 'filters': { 11 | 'require_debug_false': { 12 | '()': 'django.utils.log.RequireDebugFalse', 13 | }, 14 | 'require_debug_true': { 15 | '()': 'django.utils.log.RequireDebugTrue', 16 | }, 17 | }, 18 | 'formatters': { 19 | 'django.server': { 20 | '()': 'django.utils.log.ServerFormatter', 21 | 'format': '[%(server_time)s] %(message)s', 22 | } 23 | }, 24 | 'handlers': { 25 | 'console': { 26 | 'level': 'INFO', 27 | 'filters': ['require_debug_true'], 28 | 'class': 'logging.StreamHandler', 29 | }, 30 | # Custom handler which we will use with logger 'django'. 31 | # We want errors/warnings to be logged when DEBUG=False 32 | 'console_on_not_debug': { 33 | 'level': 'WARNING', 34 | 'filters': ['require_debug_false'], 35 | 'class': 'logging.StreamHandler', 36 | }, 37 | 'django.server': { 38 | 'level': 'INFO', 39 | 'class': 'logging.StreamHandler', 40 | 'formatter': 'django.server', 41 | }, 42 | 'mail_admins': { 43 | 'level': 'ERROR', 44 | 'filters': ['require_debug_false'], 45 | 'class': 'django.utils.log.AdminEmailHandler' 46 | } 47 | }, 48 | 'loggers': { 49 | 'django': { 50 | 'handlers': ['console', 'mail_admins', 'console_on_not_debug'], 51 | 'level': 'INFO', 52 | }, 53 | 'django.server': { 54 | 'handlers': ['django.server'], 55 | 'level': 'INFO', 56 | 'propagate': False, 57 | }, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /project_name/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbozee/django-micro/64ffdb92e494b3ccd3e40e8f568e9f70d2651d18/project_name/tests/__init__.py -------------------------------------------------------------------------------- /project_name/urls.py: -------------------------------------------------------------------------------- 1 | """django_app URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.urls import path 17 | from django.http import JsonResponse 18 | 19 | 20 | def sample_request(request): 21 | return JsonResponse({"message": "hello world"}) 22 | 23 | urlpatterns = [ 24 | path('', sample_request), 25 | ] 26 | -------------------------------------------------------------------------------- /project_name/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for authentication_service project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", 15 | "{{project_name}}.settings.production") 16 | 17 | application = get_wsgi_application() 18 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | # -- FILE: pytest.ini (or tox.ini) 2 | [pytest] 3 | DJANGO_SETTINGS_MODULE = {{project_name}}.settings.local 4 | # -- recommended but optional: 5 | addopts = --reuse-db -------------------------------------------------------------------------------- /requirements/base.txt: -------------------------------------------------------------------------------- 1 | django 2 | django-environ 3 | psycopg2-binary 4 | django-cors-headers 5 | requests>=2.20.0 6 | uvicorn -------------------------------------------------------------------------------- /requirements/local.txt: -------------------------------------------------------------------------------- 1 | -r base.txt 2 | 3 | django-extensions -------------------------------------------------------------------------------- /requirements/production.txt: -------------------------------------------------------------------------------- 1 | -r base.txt 2 | 3 | gunicorn 4 | -------------------------------------------------------------------------------- /requirements/test.txt: -------------------------------------------------------------------------------- 1 | -r local.txt 2 | 3 | pytest-django==3.2.1 4 | pytest-mock -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | from {{project_name}}.wsgi import application 2 | from v2 import app as asgi_app 3 | from cv_utils.starlette import initialize_router 4 | 5 | app = initialize_router( 6 | [{"path": "/v2", "app": asgi_app}, {"path": "", "app": application, "wsgi": True}] 7 | ) 8 | -------------------------------------------------------------------------------- /v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbozee/django-micro/64ffdb92e494b3ccd3e40e8f568e9f70d2651d18/v2/__init__.py -------------------------------------------------------------------------------- /v2/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbozee/django-micro/64ffdb92e494b3ccd3e40e8f568e9f70d2651d18/v2/tests/__init__.py -------------------------------------------------------------------------------- /v2/tests/conftest.py: -------------------------------------------------------------------------------- 1 | # your test above the import 2 | 3 | from cv_utils.tests import * 4 | --------------------------------------------------------------------------------