Skip to content
This repository has been archived by the owner on Sep 27, 2022. It is now read-only.

Ease bootstrapping and add setup.py for optional packaging #17

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
28 changes: 28 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# http://editorconfig.org
# from https://github.com/pydanny/cookiecutter-django

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{py,rst,ini}]
indent_style = space
indent_size = 4

[*.{html,css,scss,json,yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab

[nginx.conf]
indent_style = space
indent_size = 2
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,6 @@ ENV/

# SQLite3
db.sqlite3

# IDE
.idea/
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@

This repo is functionality complete — PR's and issues welcome!


## Prerequisites

* Python 3.4+
* Git
* Shell prompt ([Git BASH for windows](https://gitforwindows.org/) recommended for windows)


## Installation

1. Clone this repository: `git clone [email protected]:gothinkster/productionready-django-api.git`.
2. `cd` into `conduit-django`: `cd productionready-django-api`.
3. Install [pyenv](https://github.com/yyuu/pyenv#installation).
4. Install [pyenv-virtualenv](https://github.com/yyuu/pyenv-virtualenv#installation).
5. Install Python 3.5.2: `pyenv install 3.5.2`.
6. Create a new virtualenv called `productionready`: `pyenv virtualenv 3.5.2 productionready`.
7. Set the local virtualenv to `productionready`: `pyenv local productionready`.
8. Reload the `pyenv` environment: `pyenv rehash`.
1. Clone this repository: `git clone [email protected]:gothinkster/django-realworld-example-app.git`.
2. `cd` into `django-realworld-example-app`.
3. Bootstrap the environment `bin/bootstrap.sh`

Django local dev server should now be serving on port 4000

If all went well then your command line prompt should now start with `(productionready)`.

If your command line prompt does not start with `(productionready)` at this point, try running `pyenv activate productionready` or `cd ../productionready-django-api`.
#### Notes

If pyenv is still not working, visit us in the Thinkster Slack channel so we can help you out.
* `python` should be Python 3.4+, check using `python --version`. To be explicit, if on Linux/MacOS you may have a `python3.5` or `python3.6` on your path.
* If using windows use `venv\Scripts\python` instead of `venv/bin/python`
6 changes: 6 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TODO namespace APIs into apps/api/
TODO add tests (prefer unittest for now)
TODO rm django-extensions (not used?)
TODO marry CORS_ORIGIN_WHITELIST with ALLOW_HOSTS
TODO form opinion on dev/staging/prod settings split (perfer common.py pattern with some settings imported from ini at root)
TODO move config to root https://github.com/agconti/cookiecutter-django-rest/pull/571/files
52 changes: 52 additions & 0 deletions bin/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -e # fail fast

# bootstraps to django dev server from start to finish

CWD="$(cd "$(dirname "$0")" && pwd)"
pushd $CWD/..

DJANGO_PORT='4000'

function create_venv() {
echo "Creating venv/ using system $(python3 --version) ..."
python3 -m venv venv/ --clear

echo "Upgrading packaging tools in venv..."
venv/bin/pip install --upgrade --ignore-installed pip
venv/bin/pip install --upgrade setuptools wheel
}

function install_app() {
echo "Installing conduit from setup.py ..."
venv/bin/pip install -e .
}

function migrate() {
rm -rf *.sqlite3
bin/django.sh migrate
echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', '[email protected]', 'admin')" | bin/django.sh shell
}

function collectstatic() {
bin/django.sh collectstatic --link --noinput
}

function runserver() {
echo "Starting dev server, login to http://$(hostname -I | cut -d' ' -f1):${DJANGO_PORT} with [email protected]/admin"
bin/django.sh runserver 0.0.0.0:${DJANGO_PORT}
}

function main() {
create_venv
install_app
migrate
# collectstatic
runserver
}

if [ $# -eq 0 ]; then
main
elif [ $# -eq 1 ]; then
"$@" # call func by name ie. $ ./bootstrap.sh runserver
fi
7 changes: 7 additions & 0 deletions bin/django.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e # fail fast

CWD="$(cd "$(dirname "$0")" && pwd)"
pushd $CWD/..

venv/bin/python manage.py $1 ${@:2}
10 changes: 10 additions & 0 deletions bin/regen_requirements.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Use this script to regenerate requirements.txt from packages installed in venv/ using pipdeptree's nice tree layout

CWD="$(cd "$(dirname "$0")" && pwd)"
pushd $CWD/..

echo "Generating new requirements.txt ..."
venv/bin/pipdeptree --local-only --freeze --exclude pip,setuptools,wheel,conduit > requirements.txt

popd
26 changes: 26 additions & 0 deletions conduit/apps/core/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from django.contrib import admin
from django.db.models.fields.related import ManyToManyField


def auto_register(model):
""" Auto-register all models incl Django and 3rd party models (obviously not for production)

Based on: http://technowhisp.com/2017/08/13/django/auto-registering-models-in-django-admin/
"""
# Get all fields from model, but exclude autocreated reverse relations and ManyToManyField
field_list = [f.name for f in model._meta.get_fields() if f.auto_created == False and not isinstance(f, ManyToManyField)]
# Dynamically create ModelAdmin class and register it.
my_admin = type('MyAdmin', (admin.ModelAdmin,),
{'list_display': field_list}
)
try:
admin.site.register(model, my_admin)
except admin.sites.AlreadyRegistered:
# This model is already registered
pass


from django.apps import apps

for model in apps.get_models():
auto_register(model)
26 changes: 25 additions & 1 deletion conduit/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""

import os
import socket

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Expand All @@ -25,8 +26,30 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

def get_ip():
""" Cross-platform method of getting primary internal IP
https://stackoverflow.com/a/28950776/2819573
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except:
IP = '127.0.0.1'
finally:
s.close()
return IP

INTERNAL_IP = get_ip()

ALLOWED_HOSTS = [
INTERNAL_IP,
'.lvh.me',
'localhost',
'0.0.0.0'
]

# Application definition

Expand Down Expand Up @@ -132,6 +155,7 @@
CORS_ORIGIN_WHITELIST = (
'0.0.0.0:4000',
'localhost:4000',
INTERNAL_IP + ':4000',
)

# Tell Django about the custom `User` model we created. The string
Expand Down
10 changes: 6 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Django==1.10.5
Django==1.11.14
pytz==2018.5
django-cors-middleware==1.3.1
django-extensions==1.7.1
djangorestframework==3.4.4
PyJWT==1.4.2
six==1.10.0
six==1.10.0
djangorestframework==3.8.2
pipdeptree==0.13.0
PyJWT==1.6.4
48 changes: 48 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import os

from setuptools import find_packages, setup

CWD = os.path.dirname(__file__) # FIXME __file__ is not freeze-proof

with open(os.path.join(CWD, 'README.md')) as readme:
README = readme.read()

with open(os.path.join(CWD, 'requirements.txt')) as f:
install_reqs = [
s for s in [
line.strip(' \n') for line in f
] if not s.startswith('#') and s != ''
]

# allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))

setup(
name='conduit', # FYI this clashes with an existing package on PYPI!
version='0.1',
packages=find_packages(),
include_package_data=True,
license='BSD License', # example license
description='Example Django DRF codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld API spec.',
long_description=README,
url='https://github.com/gothinkster/realworld-example-apps',
author='Your Name',
author_email='[email protected]',
install_requires=install_reqs,
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Framework :: Django :: 1.11',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
)