From b62cde6519c0f4eb49a8c7d675195e1787dfc441 Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:10:24 +0100 Subject: [PATCH 1/9] conf: Add INTERNAL_IP to settings for externel 192.168.x.x access --- conduit/settings.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/conduit/settings.py b/conduit/settings.py index 17b2df7..bd8d9d6 100644 --- a/conduit/settings.py +++ b/conduit/settings.py @@ -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__))) @@ -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 @@ -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 From 8506c04d664ed56ec29dc86f965eda98036eed62 Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:10:54 +0100 Subject: [PATCH 2/9] deps: upgrade Django, DRF and PyJWT --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 6eb9d54..65c0ff7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -Django==1.10.5 +Django==1.11.14 django-cors-middleware==1.3.1 django-extensions==1.7.1 -djangorestframework==3.4.4 -PyJWT==1.4.2 +djangorestframework==3.8.2 +PyJWT==1.6.4 six==1.10.0 From aa5af82465aea06c208a5494183d3ff331d9fbbc Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:12:03 +0100 Subject: [PATCH 3/9] conf: remove pyenv from README, just use python 3.3+ venv * Add Prerequisites of python 3.4 and git --- README.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a90f2e3..12d6179 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,26 @@ 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 git@github.com: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 git@github.com:gothinkster/django-realworld-example-app.git`. +2. `cd` into `django-realworld-example-app`. +3. Create a new virtualenv `python -m venv venv/` +4. Install requirements `venv/bin/pip install -r requirements.txt` +5. Create database `venv/bin/python manage.py migrate` +6. Create superuser `venv/bin/python manage.py createsuperuser` +7. Run dev server `venv/bin/python manage.py runserver 0.0.0.0: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` From ae8c024b155eb70f2c779768d6da012196e04647 Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:12:42 +0100 Subject: [PATCH 4/9] conf: add a .editorconfig from pydanny/cookiecutter-django --- .editorconfig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3ac8c47 --- /dev/null +++ b/.editorconfig @@ -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 From b50e3be014680a3cec18610e5fcb4d22ab7be921 Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:12:59 +0100 Subject: [PATCH 5/9] conf: add jetbrains .idea to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2b00f1b..b63e4c5 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,6 @@ ENV/ # SQLite3 db.sqlite3 + +# IDE +.idea/ From bed39e88669065b553ba091c1dc67e73449fd22e Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:13:11 +0100 Subject: [PATCH 6/9] add a TODO --- TODO | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..54e16f1 --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ +TODO add admin +TODO namespace APIs into apps/api/ +TODO use pipdeptree to freeze all requirements +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 +TODO add setup.py for packaging as reusable django app (src and wheel) From 914d280e291452a42ea4c5993f593b65719b275d Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 13:49:16 +0100 Subject: [PATCH 7/9] add very naive auto-generated admin * Register all models and all non m2m fields --- TODO | 1 - conduit/apps/core/admin.py | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 conduit/apps/core/admin.py diff --git a/TODO b/TODO index 54e16f1..9b26bcd 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ -TODO add admin TODO namespace APIs into apps/api/ TODO use pipdeptree to freeze all requirements TODO add tests (prefer unittest for now) diff --git a/conduit/apps/core/admin.py b/conduit/apps/core/admin.py new file mode 100644 index 0000000..d77aaa6 --- /dev/null +++ b/conduit/apps/core/admin.py @@ -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) From 6ce0a48eb5d6183bfa95c8ee9e3cdef332bfde31 Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 14:09:40 +0100 Subject: [PATCH 8/9] conf: add pip/setuptools/wheel upgrade step to README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 12d6179..a14b14a 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,11 @@ This repo is functionality complete — PR's and issues welcome! 1. Clone this repository: `git clone git@github.com:gothinkster/django-realworld-example-app.git`. 2. `cd` into `django-realworld-example-app`. 3. Create a new virtualenv `python -m venv venv/` -4. Install requirements `venv/bin/pip install -r requirements.txt` -5. Create database `venv/bin/python manage.py migrate` -6. Create superuser `venv/bin/python manage.py createsuperuser` -7. Run dev server `venv/bin/python manage.py runserver 0.0.0.0:4000` +4. Upgrade python packaging tools `venv/bin/python -m pip install -U pip setuptools wheel` +5. Install requirements `venv/bin/pip install -r requirements.txt` +6. Create database `venv/bin/python manage.py migrate` +7. Create superuser `venv/bin/python manage.py createsuperuser` +8. Run dev server `venv/bin/python manage.py runserver 0.0.0.0:4000` #### Notes From 5418e1abd8fea8ebc8b522022351ed3f85137b68 Mon Sep 17 00:00:00 2001 From: ciarancourtney Date: Wed, 11 Jul 2018 15:26:43 +0100 Subject: [PATCH 9/9] conf: Add setup.py for packaging and bin/bootstrap.sh * Use pipdeptree to manage deps, just upgrade with pip and run bin/regen_requirements.sh * Parse requirements.txt in setup.py for package install * Add bin/django.sh for easy django cmds with default settings and venv --- README.md | 9 +++---- TODO | 2 -- bin/bootstrap.sh | 52 +++++++++++++++++++++++++++++++++++++++ bin/django.sh | 7 ++++++ bin/regen_requirements.sh | 10 ++++++++ requirements.txt | 4 ++- setup.py | 48 ++++++++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 9 deletions(-) create mode 100755 bin/bootstrap.sh create mode 100755 bin/django.sh create mode 100755 bin/regen_requirements.sh create mode 100644 setup.py diff --git a/README.md b/README.md index a14b14a..2f11ca0 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,9 @@ This repo is functionality complete — PR's and issues welcome! 1. Clone this repository: `git clone git@github.com:gothinkster/django-realworld-example-app.git`. 2. `cd` into `django-realworld-example-app`. -3. Create a new virtualenv `python -m venv venv/` -4. Upgrade python packaging tools `venv/bin/python -m pip install -U pip setuptools wheel` -5. Install requirements `venv/bin/pip install -r requirements.txt` -6. Create database `venv/bin/python manage.py migrate` -7. Create superuser `venv/bin/python manage.py createsuperuser` -8. Run dev server `venv/bin/python manage.py runserver 0.0.0.0:4000` +3. Bootstrap the environment `bin/bootstrap.sh` + +Django local dev server should now be serving on port 4000 #### Notes diff --git a/TODO b/TODO index 9b26bcd..7c99535 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,6 @@ TODO namespace APIs into apps/api/ -TODO use pipdeptree to freeze all requirements 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 -TODO add setup.py for packaging as reusable django app (src and wheel) diff --git a/bin/bootstrap.sh b/bin/bootstrap.sh new file mode 100755 index 0000000..98becaa --- /dev/null +++ b/bin/bootstrap.sh @@ -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', 'admin@example.com', '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 admin@example.com/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 diff --git a/bin/django.sh b/bin/django.sh new file mode 100755 index 0000000..8eb5824 --- /dev/null +++ b/bin/django.sh @@ -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} diff --git a/bin/regen_requirements.sh b/bin/regen_requirements.sh new file mode 100755 index 0000000..ed21ffb --- /dev/null +++ b/bin/regen_requirements.sh @@ -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 diff --git a/requirements.txt b/requirements.txt index 65c0ff7..8a76549 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,8 @@ Django==1.11.14 + pytz==2018.5 django-cors-middleware==1.3.1 django-extensions==1.7.1 + six==1.10.0 djangorestframework==3.8.2 +pipdeptree==0.13.0 PyJWT==1.6.4 -six==1.10.0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ea09fac --- /dev/null +++ b/setup.py @@ -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='yourname@example.com', + 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', + ], +)