{"id":24911576,"url":"https://github.com/hackoregon/2019-backend-docker","last_synced_at":"2026-06-23T12:33:07.450Z","repository":{"id":75397820,"uuid":"184358785","full_name":"hackoregon/2019-backend-docker","owner":"hackoregon","description":"Base Docker image for 2019 Backend API projects","archived":false,"fork":false,"pushed_at":"2019-09-25T23:09:17.000Z","size":70,"stargazers_count":3,"open_issues_count":3,"forks_count":0,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-28T03:15:01.890Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hackoregon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-01T02:22:35.000Z","updated_at":"2019-09-11T02:58:45.000Z","dependencies_parsed_at":"2023-06-06T09:30:44.588Z","dependency_job_id":null,"html_url":"https://github.com/hackoregon/2019-backend-docker","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hackoregon/2019-backend-docker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackoregon%2F2019-backend-docker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackoregon%2F2019-backend-docker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackoregon%2F2019-backend-docker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackoregon%2F2019-backend-docker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hackoregon","download_url":"https://codeload.github.com/hackoregon/2019-backend-docker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackoregon%2F2019-backend-docker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34688124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-02T04:21:06.142Z","updated_at":"2026-06-23T12:33:07.426Z","avatar_url":"https://github.com/hackoregon.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hack Oregon 2019 Backend Docker - Django\n\n|Build|Travis|DockerHub|\n|-|-|-|\n| Staging (Development) | [![Build Status](https://travis-ci.org/hackoregon/2019-backend-docker.svg?branch=staging)](https://travis-ci.org/hackoregon/2019-backend-docker) | [![](https://images.microbadger.com/badges/version/hackoregoncivic/backend-docker-django-dev.svg)](https://microbadger.com/images/hackoregoncivic/backend-docker-django-dev \"Get your own version badge on microbadger.com\") |\n| Master (Production) | [![Build Status](https://travis-ci.org/hackoregon/2019-backend-docker.svg?branch=master)](https://travis-ci.org/hackoregon/2019-backend-docker) | [![](https://images.microbadger.com/badges/version/hackoregoncivic/backend-docker-django.svg)](https://microbadger.com/images/hackoregoncivic/backend-docker-django \"Get your own version badge on microbadger.com\") |\n\nThis repository contains the source files for the Docker Image for the 2019 Hack Oregon Season.\n\n## What is Hack Oregon?\n\n[Hack Oregon](http://www.hackoregon.org/) is a rapid prototyping lab taking a creative approach to\ndata projects that bring insight to complex issues in the public\ninterest. We’re a community-powered nonprofit, our teams are made of\nvolunteers, and all the work we do is open source.\n\n## Features\n\n* Provide a base Django Rest Framework Application using Python 3+/Django2+\n* Include pre-configuration for CORS headers and whitenoise for static asset hosting\n* Provide support to connecting to a PostgreSQL 11 and PostGIS/GeoDjango\n* Provide a Database Router for connecting to multiple DATABASES\n* Provide a standardized method for maintaining/updating core Hack Oregon dependencies/settings\n* Published to Docker Hub through Travis CI/CD pipeline\n* Gunicorn server with configuration file\n* 2 stage deploys:\n  - `staging` branch deploys to the `hackoregoncivic/backend-docker-django-dev` Dockerhub repo.\n  - `master` branch deploys to the `hackoregoncivic/backend-docker-django` Dockerhub repo.\n\n## Getting Started\n\nHack Oregon Projects will make use of this image via the Dockerfile provided in the [2019-backend-cookiecutter-django](https://github.com/hackoregon/2019-backend-cookiecutter-django) repository and will generally not interact with this repo directly. Full setup steps will be in the mentioned repo.\n\n### For uses outside of Hack Oregon:\n\nThis repo is intended to be a base image for Django Rest Framework APIs. It's intended to enforce certain conventions while allowing for individual project configuration. The image will work best when using a local Dockerfile as well as Docker-Compose:\n\n1. Create your local Dockerfile. Here is an example to get you started:\n\n```\n## Add -dev to dockername to pull from development repo\nFROM hackoregoncivic/backend-docker-django\nENV PYTHONUNBUFFERED 1\n\n## Moves into main directory of image\nWORKDIR /code\n\n## copy your local requirements\nCOPY requirements.txt /code/\n\n## copy your django settings overrides and url overrides\nCOPY local_settings /code/local_settings/\n\n## install requirments\nRUN pip install -r requirements.txt\nRUN python\n\n## copy entrypoint and any other startup files\nCOPY bin /code/bin/\n\n## give execution perms on manage.py/other python files\nRUN chmod +x *.py\n\n## run your entrypoint file\nENTRYPOINT [ \"/code/bin/docker-entrypoint.sh\" ]\n```\n\n2. Create a .env file in root folder to pass in environment variables.  If you add the Postgres related vars, app will use postgres, otherwise defaults to sqlite3.\n\nExample:\n```\nDEBUG=true\nPOSTGRES_USER=transportation-systems\nPOSTGRES_NAME=transportation-systems-main\nPOSTGRES_HOST=54.202.102.40\nPOSTGRES_PASSWORD=Z6mHewT5He75\nDJANGO_SECRET_KEY=h0ldon2th3nighT\n```\n\n3. Create a local_settings folder which will contain 3 files: `settings.py`, `urls.py`, and `gunicorn_conf.py`. These files will include any Django settings for your project, that you need to override from the default, as well as your url routes, and [gunicorn webserver configuration](http://docs.gunicorn.org/en/stable/settings.html#settings) respectively. If you are just spinning up the default hello world django project, and not adding any additional url routes, omit the `urls.py` or a blank file will cause errors.\n\nFor example, if you are working to create a local django app named `passenger_census` you would like to import, you can include you updated `INSTALLED_APPS` object in the `local_settings/settings.py` and it will be imported.\n\n```\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'corsheaders',\n    'django_filters',\n    'rest_framework',\n    'rest_framework_gis',\n    'rest_framework_swagger',\n    'passenger_census'\n]\n```\n\nAnd an example `urls.py`, which creates a swagger view and route for urls in package:\n\n```\n\"\"\"backend URL Configuration\n\nThe `urlpatterns` list routes URLs to views. For more information please see:\n    https://docs.djangoproject.com/en/2.0/topics/http/urls/\nExamples:\nFunction views\n    1. Add an import:  from my_app import views\n    2. Add a URL to urlpatterns:  path('', views.home, name='home')\nClass-based views\n    1. Add an import:  from other_app.views import Home\n    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')\nIncluding another URLconf\n    1. Import the include() function: from django.urls import include, path\n    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))\n\"\"\"\nfrom django.conf.urls import url, include\nfrom django.urls import path\nfrom rest_framework.routers import DefaultRouter\n\nfrom rest_framework_swagger.views import get_swagger_view\n\n\nschema_view = get_swagger_view(title='Hack Oregon 2018 Transportation Systems APIs')\n\nurlpatterns = [\n    url(r'^transportation-systems/$', schema_view),\n    url(r'^transportation-systems/passenger-census/', include('hackoregon_transportation_systems.passenger_census.urls')),\n]\n```\n\n4. Create a requirements file for any pip requirements. Using the above Dockerfile, this would be in your project root folder, and named `requirements.txt`.\n\n5. Create a Docker Compose file to configure the Docker stack for starting up. If you are connecting to an external database, you should just need to configure the api container.\n\nHere is example file to get you started:\n\n```\nversion: '3.4'\nservices:\n  api:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    image: api\n    command: ./bin/docker-entrypoint.sh\n    volumes:\n      - ./src_files\n    ports:\n      - \"8000:8000\"\n    environment:\n      - PROJECT_NAME=${PROJECT_NAME}\n      - DEBUG=True\n      - POSTGRES_USER=${POSTGRES_USER}\n      - POSTGRES_NAME=${POSTGRES_NAME}\n      - POSTGRES_HOST=${POSTGRES_HOST}\n      - POSTGRES_PORT=${POSTGRES_PORT}\n      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n      - DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY}\n```\nThis will spin up a local docker image named `api`, which builds based on the provided Dockerfile, passing in the environmental variables from your .env file, and startup based on a `docker-entrypoint.sh` script.\n\n6. Create a bin folder, to house a `docker-entrypoint.sh` and any other startup files.\n\n7. Within bin folder, create a `docker-entrypoint.sh` file to run startup script.\n\nExample (Please note that copy and pasting from Dockerhub may cause some of the special characters in this example to become url-encoded, which may cause issues when attempting to run. Double check the file if you run into errors.):\n\n```\n#! /bin/bash\n\n# wait-for-postgres.sh\n# https://docs.docker.com/compose/startup-order/\n\n# http://linuxcommand.org/lc3_man_pages/seth.html:\n# -e  Exit immediately if a command exits with a non-zero status.\nset -e\n\nif [ \"$POSTGRES_NAME\" ]; then\n  export PGPASSWORD=$POSTGRES_PASSWORD\n  until psql -h \"$POSTGRES_HOST\" -U \"$POSTGRES_USER\" -p \"$POSTGRES_PORT\" -d postgres -c '\\q'\n  do\n    \u003e\u00262 echo \"Postgres is unavailable - sleeping\"\n    sleep 5\n  done\nfi\n\n\u003e\u00262 echo \"Postgres is up\"\necho Debug: $DEBUG\nchmod +x *.py\n\necho \"Make migrations\"\npython -Wall manage.py makemigrations\n\necho \"Migrate\"\npython -Wall manage.py migrate\n\n# Collect static files\necho \"Collect static files\"\npython -Wall manage.py collectstatic --noinput\n\necho \"Run server...\"\npython -Wall manage.py runserver 0.0.0.0:8000\n```\n\n8. With this setup, you should be ready to startup an app.\n\nFirst you can build your application:\n\n```\n$ docker-compose build\n```\n\nThen start your application:\n\n```\n$ docker-compose up\n```\n\n\n## About the `DEBUG` variable\n\nThis repo allows user to set a `DEBUG` variable to `true` or `false`\n\nFollowing actions happen when variable is set to `true`:\n\n* Disables push to ECS services from `master` branch\n* ENV VARS are read from local .env (not Parameter Store)\n* Sets Django App to Debug mode (See: [Django Docs](https://docs.djangoproject.com/en/2.2/ref/settings/#debug))\n* Provides lower level logging, including SQL queries for troubleshooting\n\nFollowing actions happen when variable is set to `false`:\n\n* Allows push to ECS services from `master` branch\n* If not in a Travis Build, will pull env vars from Parameter Store. (Travis will pull based on env vars set in Travis console)\n* Django App DEBUG set to `False`\n* Logging is restricted\n\n## Gunicorn and WhiteNoise\n\nThis container uses Gunicorn as a Python WSGI HTTP Server for serving the API/data layer. A basic config file is included within this repo. It can import an additional `gunicorn_conf.py` file from your `local_settings` directory. (See: [Gunicorn Settings Docs](http://docs.gunicorn.org/en/latest/settings.html))\n\nInstead of running an additional web server for static files, we are hosting our Swagger/static assets through the use of `WhiteNoise` whith in the same server. Read [this](http://whitenoise.evans.io/en/stable/#infrequently-asked-questions) for more info on why we are choosing this configuration\n\n## PostgreSQL and Database router\n\nProject will add the `apt.postgresql.org` to source.list and install a PostgreSQL 11.2 client within container, and performs a `wait-for` script to wait for database to connect before loading application.\n\nProject will check for the `POSTGRES_NAME` variable to be set, otherwise will default to `sqlite3`\n\nProject does contain POSTGIS support as well.\n\nAdditionally the Django Project contains a database router (router.py). This router allows project to connect to multiple databases. The database to connect to can then be set on a per model basis within your application using an \"in_db\" field.\n\nFor example, let's say you have a database split into partitions, and setup each partition as a separate database in your `local_settings/settings.py`:\n\n```\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.contrib.gis.db.backends.postgis',\n        'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),\n        'NAME': os.environ.get('POSTGRES_NAME'),\n        'USER': os.environ.get('POSTGRES_USER'),\n        'HOST': os.environ.get('POSTGRES_HOST'),\n        'PORT': os.environ.get('POSTGRES_PORT')\n    },\n    'multnomah_county_permits': {\n        'ENGINE': 'django.contrib.gis.db.backends.postgis',\n        'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),\n        'OPTIONS': {\n                'options': '-c search_path=django,public,multnomah_county_permits'\n            },\n        'NAME': os.environ.get('POSTGRES_NAME'),\n        'USER': os.environ.get('POSTGRES_USER'),\n        'HOST': os.environ.get('POSTGRES_HOST'),\n        'PORT': os.environ.get('POSTGRES_PORT')\n    },\n    'passenger_census': {\n        'ENGINE': 'django.contrib.gis.db.backends.postgis',\n        'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),\n        'OPTIONS': {\n                'options': '-c search_path=django,passenger_census'\n            },\n        'NAME': os.environ.get('POSTGRES_NAME'),\n        'USER': os.environ.get('POSTGRES_USER'),\n        'HOST': os.environ.get('POSTGRES_HOST'),\n        'PORT': os.environ.get('POSTGRES_PORT')\n    }\n  }\n  ```\n\nYou can then add the following to your `models.py`:\n\n```\nimport django.db.models.options as options\noptions.DEFAULT_NAMES = options.DEFAULT_NAMES + ('in_db',)\n```\n\nAnd then specify a particular model uses a specific database:\n\n```\nclass AnnualCensusBlockRidership(models.Model):\n    year = models.IntegerField(blank=True, null=True)\n    census_block = models.CharField(max_length=255, blank=True, null=True)\n    total_ons = models.BigIntegerField(blank=True, null=True)\n    stops = models.BigIntegerField(blank=True, null=True)\n    geom_polygon_4326 = models.GeometryField(blank=True, null=True)\n\n    class Meta:\n        managed = False\n        db_table = 'annual_census_block_ridership'\n        in_db = 'passenger_census'\n```\n\n## Development of the Docker IMAGE\n\nThis repo uses Travis for a CI/CD deployment of image to Docker Hub. Upon a merged pull request to the 'STAGING' branch, an image will be pushed to the `hackoregoncivic/backend-docker-django-dev` branch. This image can then be pulled for testing purposes with a live database.\n\nWhen files are merged to `MASTER`, image will then de deployed to the `hackoregoncivic/backend-docker-django` repo. All Hack Oregon teams should use this repo for API development as well as production use.\n\nThings to note:\n\n* Deploy/Infra scripts should be housed in the `bin` folder\n* The core Django files have been left relatively intact from generating a default project. This should allow for forward compatible code. Any updates/changes to the Django settings should be done in the `backend/hacko_settings.py` file, not the default settings.\n* The `backend/settings.py`, `backend/urls.py`, and `gunicorn_conf.py` are each configured to import their respective files from a user's `local_settings` folder. If these do not exist, then they will be passed over silently. If you change/update these files during development for any reason, be sure to keep imports at the bottom of each file.\n\nFor example `backend/settings.py` imports the `hacko_settings`:\n\n```\ntry:\n    from backend.hacko_settings import *\nexcept ImportError:\n    pass\n\n```\n\nThen `hacko_settings` will import your `local_settings/settings` (assumes you have set the `src_files` volume in your docker_compose):\n\n```\ntry:\n    from src_files.local_settings.settings import *\nexcept ImportError:\n    pass\n```\n* Python requirements will be installed from the `requirements/common.txt`. We have been following pattern of \u003e=current version, \u003cnext major version. This should allow robustness, and responsiveness to updates, within minimizing breaking changes. If we run into issues, we may want to pin to minor versions...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackoregon%2F2019-backend-docker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhackoregon%2F2019-backend-docker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackoregon%2F2019-backend-docker/lists"}