Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bfirsh committed Apr 1, 2020
0 parents commit d43f3b9
Show file tree
Hide file tree
Showing 36 changed files with 7,844 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"presets": [
"@babel/preset-env"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
15 changes: 15 additions & 0 deletions .devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// See https://aka.ms/vscode-remote/devcontainer.json for format details.
{
"dockerFile": "Dockerfile",
// Mount workdir under /code
"workspaceMount": "src=${localWorkspaceFolder},dst=/code,type=bind,consistency=delegated",
"workspaceFolder": "/code",
// HACK: use node_modules from inside image
"runArgs": ["-v", "/code/node_modules"],
"extensions": [
"ms-python.python",
"sibiraj-s.vscode-scss-formatter",
"esbenp.prettier-vscode",
"batisteo.vscode-django"
]
}
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__pycache__
*.pyc
.env
.cache
node_modules
{{ project_name }}/static/dist
{{ project_name }}/static_root
.env
/local
media
yarn-error.log
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["react-app"]
}
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: CI

on: [push]

jobs:

test:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: Test
run: script/test
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
__pycache__
*.pyc
.env
.cache
node_modules
{{ project_name }}/static/dist
{{ project_name }}/static_root
.env
/local
media
yarn-error.log
.vscode/tags
15 changes: 15 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"editor.formatOnSave": true,
"files.associations": {
"**/*.html": "html",
"**/templates/**/*.html": "django-html",
"**/templates/**/*": "django-txt"
},
"python.formatting.provider": "black",
"python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintArgs": [
"--load-plugins",
"pylint_django",
"--disable=C0111"
]
}
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM python:3.8.2
ENV PYTHONUNBUFFERED 1
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb http://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
# runs apt-get update
&& curl -sL https://deb.nodesource.com/setup_12.x | bash - \
&& apt-get install -yq \
exuberant-ctags \
netcat \
nodejs \
postgresql-client \
yarn
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY package.json yarn.lock /code/
RUN yarn install
COPY . /code/
RUN yarn build
RUN SECRET_KEY=unset python manage.py collectstatic --no-input
ENV WEB_CONCURRENCY 3
ENV WORKER_CONNECTIONS 50
ENV PORT 8000
CMD gunicorn {{ project_name }}.wsgi -k gevent --worker-connections $WORKER_CONNECTIONS --bind 0.0.0.0:$PORT --config gunicorn_config.py --max-requests 10000 --max-requests-jitter 1000 --access-logfile -
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Django template for Docker + Heroku

This is a template for Django applications that can be run with Docker Compose locally and Heroku in production.

It is how I set up Django projects to get up and running as quick as possible. In includes a few neat things:

- Static file compilation with Parcel, so you can use modern JS stuff and SCSS
- Static file serving with Whitenoise
- CI with GitHub actions
- [VSCode remote container config](https://code.visualstudio.com/docs/remote/containers) with linting, Black, refactoring, etc, all set up sensibly
- A custom User model, which [Django recommend doing when starting a project](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#substituting-a-custom-user-model)
- [Gevent workers and DB connection pooling, so you can serve up lots of requests on a Heroku hobby dyno](https://medium.com/@bfirsh/squeezing-every-drop-of-performance-out-of-a-django-app-on-heroku-4b5b1e5a3d44)

## Getting started

To get started (replace `myapp` with the name of your app):

$ docker run -it --rm -v "$PWD":/usr/src/app -w /usr/src/app django django-admin.py startproject --template https://github.com/bfirsh/django-docker-heroku-template/zipball/master myapp
$ cd myapp

This readme file is now in your app's directory. You can delete this top bit and everything that follows is the start of your app's readme.

# {{ project_name }}

## Development environment

Install Docker, then run:

$ docker-compose up --build

This will boot up everything that your app needs to run.

(Note: the `--build` argument is not required, but will ensure the Python and JS dependencies are always up-to-date.)

In another console, run these commands to set up the database and set up a user:

$ docker-compose run web ./manage.py migrate
$ docker-compose run web ./manage.py createsuperuser

The local development environment is now running at [http://localhost:8000](http://localhost:8000). The admin interface is at [http://localhost:8000/admin/](http://localhost:8000/admin/), accessible with the user/pass created above.

## Tests

To run the test suite:

$ docker-compose run web ./manage.py test

## Deployment on Heroku

This app is designed to be deployed on Heroku.

These commands, roughly, will get you set up with an app. Replace `{{ project_name }}-production` with a name for the app:

```
$ heroku update beta
$ heroku plugins:install @heroku-cli/plugin-manifest
$ heroku apps:create --manifest --no-remote --stack=container {{ project_name}}-production
$ heroku config:set -a {{ project_name }}-production SECRET_KEY=$(openssl rand -hex 64)
```

In the Heroku web UI, go to the app, then the "Deploy" tab, then connect it to a GitHub repo. Then, click "Deploy branch" at the bottom to trigger a deploy. `./manage.py migrate` will be run on deploy.

On this page, you can also set up automatic deploys if you want. You probably want to check "Wait for CI to pass before deploy".
15 changes: 15 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "{{ project_name }}",
"env": {
"SECRET_KEY": {
"generator": "secret"
}
},
"formation": {
"web": {
"quantity": 1
}
},
"addons": ["papertrail", "heroku-postgresql"],
"buildpacks": []
}
Empty file added assets/css/index.scss
Empty file.
6 changes: 6 additions & 0 deletions assets/js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// CSS Entrypoint
//
// We do it like this instead of specifying it as an extra target in Parcel
// because Parcel does lots of weird stuff when there are multiple entrypoints.
// e.g. https://github.com/parcel-bundler/parcel/issues/2704
import "../css/index.scss";
25 changes: 25 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: "3"

services:
db:
image: postgres:10
web:
build: .
command: python -Wd manage.py runserver 0.0.0.0:8000
environment:
DEBUG: "true"
SECRET_KEY: "not secure only use for development"
DATABASE_URL: "psql://postgres@db:5432/postgres"
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
assets:
build: .
command: sh -c "yarn && yarn start"
volumes:
- .:/code
# HACK: use node_modules from inside image instead of one on local machine
- /code/node_modules
6 changes: 6 additions & 0 deletions gunicorn_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from psycogreen.gevent import patch_psycopg


def post_fork(server, worker):
patch_psycopg()
worker.log.info("Made Psycopg2 Green")
7 changes: 7 additions & 0 deletions heroku.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
build:
docker:
web: Dockerfile
release:
image: web
command:
- ./manage.py migrate
26 changes: 26 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
from gevent import monkey
from psycogreen.gevent import patch_psycopg

monkey.patch_all()
patch_psycopg()


def main():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == "__main__":
main()
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "{{ project_name }}",
"version": "1.0.0",
"scripts": {
"build": "parcel build --no-autoinstall -d {{ project_name }}/static/dist assets/js/index.js",
"start": "parcel watch --no-autoinstall --no-hmr -d {{ project_name }}/static/dist assets/js/index.js"
},
"dependencies": {},
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/plugin-proposal-class-properties": "^7.7.0",
"@babel/preset-env": "^7.7.1",
"@typescript-eslint/eslint-plugin": "2.x",
"@typescript-eslint/parser": "2.x",
"babel-eslint": "10.x",
"eslint": "6.x",
"eslint-config-react-app": "^5.0.2",
"eslint-plugin-flowtype": "4.7.0",
"eslint-plugin-import": "2.x",
"eslint-plugin-jsx-a11y": "6.x",
"eslint-plugin-react": "7.x",
"eslint-plugin-react-hooks": "3.0.0",
"parcel-bundler": "^1.12.4",
"prettier": "^2.0.2",
"sass": "^1.23.6",
"webpack": "^4.41.2"
}
}
Empty file added project_name/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions project_name/context_processors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.conf import settings


# Some extra settings in templates that Django doesn't do for us
def extra_settings(request):
return {"GOOGLE_ANALYTICS_PROPERTY_ID": settings.GOOGLE_ANALYTICS_PROPERTY_ID}
Loading

0 comments on commit d43f3b9

Please sign in to comment.