diff --git a/.travis.yml b/.travis.yml index f4a2e41c5..8ca40c77a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ language: python python: 3.5 env: - - TOX_ENV=py27 - TOX_ENV=py34 - TOX_ENV=py35 diff --git a/CHANGELOG.md b/CHANGELOG.md index e614c84a9..70a142fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ All enhancements and patches to Cookiecutter Django will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [2015-10-08] +### Changed +- Elastic Beanstalk: Added --noinput to migrate command (@MightySCollins ) + +## [2015-10-07] +### Added +- Finished first pass at Elastic Beanstalk docs (@pydanny & @audreyr) +### Deleted +- Removed Heroku instant deploy button (@pydanny) + + +##[2016-09-29] +### Added +- Added default `AUTH_PASSWORD_VALIDATORS` configuration, generated by django 1.10 startproject. See [Password Validation docs](https://docs.djangoproject.com/en/1.10/topics/auth/passwords/#module-django.contrib.auth.password_validation") (@luzfcb) +- Rename `MIDDLEWARE_CLASSES` to `MIDDLEWARE` to enable support to [new style middleware](https://github.com/django/deps/blob/master/final/0005-improved-middleware.rst) introduced in Django 1.10 (@luzfcb) +- New setting `MAILGUN_SENDER_DOMAIN` to allow sending mail from any domain other than those registered with mailgun (@jangeador) +- add `urlpatterns` configuration to django-debug-toolbar, because the automatic configuration of `urlpatterns` was removed from django-debug-toolbar (@luzfcb) +- Added Temporary workaround on `requirements/local.txt` to fix django-debug-toolbar issue: https://github.com/pydanny/cookiecutter-django/issues/827 (@luzfcb) + +### Changed +- Upgrade to Django 1.10.1 (@luzfcb) +- Upgrade django-model-utils to 2.6, django-redis to 4.5.0, redis to 2.10.5, Sphinx to 1.4.6, pytest-django to 3.0.0, django-anymail to 0.5, raven to 5.27.1, whitenoise to 3.2.2 (@luzfcb) +- Upgrade to Bootstrap 4 Alpha 4, jQuery to 3.1.1, tether.js to 1.3.7 (@luzfcb) +- Update `manage.py` to use same code of `manage.py` from Django 1.10 (@luzfcb) +- Sync `sites` app migrations with django 1.10, and fix aditional migrations to `sites` and `user` app (@luzfcb) +d changed 'admin' url on `config/urls.py`, to stay the same as generated by django 1.10 (@luzfcb) +- Make test_docker.sh tests pass by passing new password auth rules (@ssteinerx) + +### Removed +- Removed django-autoslug because not support django 1.10 at this date (@luzfcb) + + ##[2016-09-10] ### Changed - Use app registry instead of INSTALLED_APPS to discover celery tasks (@dhepper) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 9acc83287..efff1fad9 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -39,9 +39,9 @@ To run all tests using various versions of python in virtualenvs defined in tox. It is possible to tests with some versions of python, to do this the command is:: - $ tox -e py27,py34 + $ tox -e py34,py35 -Will run py.test with the python2.7, and python3.4 interpreters, for +Will run py.test with the python3.4, and python3.5 interpreters, for example. To run a particular test with tox for against your current Python version:: diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 652b7bd55..11324a50a 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -16,6 +16,7 @@ Fábio C. Barrionuevo da Luz `@luzfcb`_ @luzfcb Saurabh Kumar `@theskumar`_ @_theskumar Jannis Gebauer `@jayfk`_ Burhan Khalid `@burhan`_ @burhan +Shupeyko Nikita `@webyneter`_ @webyneter =========================== ============= =========== *Audrey is also the creator of Cookiecutter. Audrey and @@ -26,6 +27,7 @@ Daniel are on the Cookiecutter core team.* .. _@theskumar: https://github.com/theskumar .. _@audreyr: https://github.com/audreyr .. _@jayfk: https://github.com/jayfk +.. _@webyneter: https://github.com/webyneter Other Contributors ------------------ @@ -58,6 +60,7 @@ Listed in alphabetical order. Benjamin Abel Bo Lopker `@blopker`_ Bouke Haarsma + Brent Payne `@brentpayne`_ @brentpayne Burhan Khalid `@burhan`_ @burhan Catherine Devlin `@catherinedevlin`_ Cédric Gaspoz `@cgaspoz`_ @@ -88,6 +91,7 @@ Listed in alphabetical order. Ian Lee `@IanLee1521`_ Jan Van Bruggen `@jvanbrug`_ Jens Nilsson `@phiberjenz`_ + Jimmy Gitonga `@afrowave`_ @afrowave Julien Almarcha `@sladinji`_ Julio Castillo `@juliocc`_ Kaido Kert `@kaidokert`_ @@ -95,6 +99,7 @@ Listed in alphabetical order. Kaveh `@ka7eh`_ Kevin A. Stone Kevin Ndung'u `@kevgathuku`_ + Keith Webber `@townie`_ Krzysztof Szumny `@noisy`_ Krzysztof Żuraw `@krzysztofzuraw`_ Leonardo Jimenez `@xpostudio4`_ @@ -104,33 +109,41 @@ Listed in alphabetical order. Lyla Fischer Martin Blech Mathijs Hoogland `@MathijsHoogland`_ + Matt Braymer-Hayes `@mattayes`_ @mattayes Matt Linares Matt Menzenski `@menzenski`_ Matt Warren `@mfwarren`_ Matthew Sisley `@mjsisley`_ Meghan Heintz `@dot2dotseurat`_ + Mesut Yılmaz `@myilmaz`_ + Michael Gecht `@mimischi`_ @_mischi mozillazg `@mozillazg`_ Pablo `@oubiga`_ Parbhat Puri `@parbhat`_ Peter Bittner `@bittner`_ Raphael Pierzina `@hackebrot`_ Raony Guimarães Corrêa `@raonyguimaraes`_ + René Muhl `@rm--`_ Roman Afanaskin `@siauPatrick`_ Roman Osipenko `@romanosipenko`_ Russell Davies - stepmr `@stepmr`_ + Sam Collins `@MightySCollins`_ + Shupeyko Nikita `@webyneter`_ Sławek Ehlert `@slafs`_ Srinivas Nyayapati `@shireenrao`_ + stepmr `@stepmr`_ Steve Steiner `@ssteinerX`_ Sule Marshall `@suledev`_ Taylor Baldwin Théo Segonds `@show0k`_ + Tim Freund `@timfreund`_ Tom Atkins `@knitatoms`_ Tom Offermann Travis McNeill `@Travistock`_ @tavistock_esq Vitaly Babiy Vivian Guillen `@viviangb`_ Will Farley `@goldhand`_ @g01dhand + William Archinal `@archinal`_ Yaroslav Halchenko ========================== ============================ ============== @@ -142,6 +155,7 @@ Listed in alphabetical order. .. _@amjith: https://github.com/amjith .. _@andor-pierdelacabeza: https://github.com/andor-pierdelacabeza .. _@antoniablair: https://github.com/antoniablair +.. _@archinal: https://github.com/archinal .. _@areski: https://github.com/areski .. _@arruda: https://github.com/arruda .. _@bittner: https://github.com/bittner @@ -186,17 +200,22 @@ Listed in alphabetical order. .. _@knitatoms: https://github.com/knitatoms .. _@krzysztofzuraw: https://github.com/krzysztofzuraw .. _@MathijsHoogland: https://github.com/MathijsHoogland +.. _@mattayes: https://github.com/mattayes .. _@menzenski: https://github.com/menzenski .. _@mfwarren: https://github.com/mfwarren +.. _@mimischi: https://github.com/mimischi .. _@mjsisley: https://github.com/mjsisley +.. _@myilmaz: https://github.com/myilmaz .. _@mozillazg: https://github.com/mozillazg .. _@noisy: https://github.com/noisy .. _@originell: https://github.com/originell .. _@oubiga: https://github.com/oubiga .. _@parbhat: https://github.com/parbhat .. _@raonyguimaraes: https://github.com/raonyguimaraes +.. _@rm--: https://github.com/rm-- .. _@romanosipenko: https://github.com/romanosipenko .. _@shireenrao: https://github.com/shireenrao +.. _@webyneter: https://github.com/webyneter .. _@show0k: https://github.com/show0k .. _@shultz: https://github.com/shultz .. _@siauPatrick: https://github.com/siauPatrick @@ -204,6 +223,7 @@ Listed in alphabetical order. .. _@ssteinerX: https://github.com/ssteinerx .. _@stepmr: https://github.com/stepmr .. _@suledev: https://github.com/suledev +.. _@timfreund: https://github.com/timfreund .. _@Travistock: https://github.com/Tavistock .. _@trungdong: https://github.com/trungdong .. _@viviangb: httpsL//github.com/viviangb @@ -214,6 +234,8 @@ Listed in alphabetical order. .. _@sladinji: https://github.com/sladinji .. _@andresgz: https://github.com/andresgz .. _@jangeador: https://github.com/jangeador +.. _@townie: https://github.com/townie +.. _@MightySCollins: https://github.com/MightySCollins Special Thanks ~~~~~~~~~~~~~~ diff --git a/README.rst b/README.rst index a0aa50778..b3ad3ab35 100644 --- a/README.rst +++ b/README.rst @@ -16,20 +16,24 @@ Powered by Cookiecutter_, Cookiecutter Django is a framework for jumpstarting pr * Documentation: https://cookiecutter-django.readthedocs.io/en/latest/ * See Troubleshooting_ for common errors and obstacles +* If you have problems with Cookiecutter Django, please open issues_ before sending emails to the maintainers. You will get a much, MUCH faster response. .. _cookiecutter: https://github.com/audreyr/cookiecutter .. _Troubleshooting: https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html .. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 +.. _issues: https://github.com/pydanny/cookiecutter-django/issues/new Features --------- -* For Django 1.9 +* For Django 1.10 +* Works with Python 3.4.x or 3.5.x. Python 3.6 is experimental * Renders Django projects with 100% starting test coverage -* Twitter Bootstrap_ v4.0.0 - `alpha 3`_ +* Twitter Bootstrap_ v4.0.0 - alpha 6 (`maintained Foundation fork`_ also available) * 12-Factor_ based settings via django-environ_ +* Secure by default. We believe in SSL. * Optimized development and production settings * Registration via django-allauth_ * Comes with custom user model ready to go @@ -39,9 +43,11 @@ Features * Docker support using docker-compose_ for development and production * Procfile_ for deploying to Heroku * Instructions for deploying to PythonAnywhere_ -* Works with Python 2.7.x or 3.5.x * Run tests with unittest or py.test * Customizable PostgreSQL version +* Experimental support for Amazon Elastic Beanstalk + +.. _`maintained Foundation fork`: https://github.com/Parbhat/cookiecutter-django-foundation Optional Integrations @@ -55,7 +61,6 @@ Optional Integrations * Integration with Sentry_ for error logging * Integration with Opbeat_ for performance monitoring -.. _`alpha 3`: http://blog.getbootstrap.com/2016/07/27/bootstrap-4-alpha-3/ .. _Bootstrap: https://github.com/twbs/bootstrap .. _django-environ: https://github.com/joke2k/django-environ .. _12-Factor: http://12factor.net/ @@ -67,7 +72,7 @@ Optional Integrations .. _Celery: http://www.celeryproject.org/ .. _Anymail: https://github.com/anymail/django-anymail .. _MailHog: https://github.com/mailhog/MailHog -.. _Sentry: https://getsentry.com/welcome/ +.. _Sentry: https://sentry.io/welcome/ .. _docker-compose: https://github.com/docker/compose .. _Opbeat: https://opbeat.com/ .. _PythonAnywhere: https://www.pythonanywhere.com/ @@ -78,7 +83,7 @@ Constraints * Only maintained 3rd party libraries are used. * Uses PostgreSQL everywhere (9.2+) -* Environment variables for configuration (This won't work with Apache/mod_wsgi). +* Environment variables for configuration (This won't work with Apache/mod_wsgi except on AWS ELB). Usage @@ -89,7 +94,7 @@ and then editing the results to include your name, email, and various configurat First, get Cookiecutter. Trust me, it's awesome:: - $ pip install cookiecutter + $ pip install "cookiecutter>=1.4.0" Now run it against this repo:: @@ -122,7 +127,6 @@ Answer the prompts with your own desired options_. For example:: use_opbeat [n]: y use_pycharm [n]: y windows [n]: n - use_python3 [y]: y use_docker [y]: n use_heroku [n]: y use_compressor [n]: y @@ -135,8 +139,7 @@ Answer the prompts with your own desired options_. For example:: Select js_task_runner: 1 - Gulp 2 - Grunt - 3 - Webpack - 4 - None + 3 - None Choose from 1, 2, 3, 4 [1]: 1 use_lets_encrypt [n]: n Select open_source_license: @@ -146,6 +149,7 @@ Answer the prompts with your own desired options_. For example:: 4 - Apache Software License 2.0 5 - Not open source Choose from 1, 2, 3, 4, 5 [1]: 1 + use_elasticbeanstalk_experimental: n Enter the project and take a look around:: @@ -187,6 +191,13 @@ For Readers of Two Scoops of Django 1.8 You may notice that some elements of this project do not exactly match what we describe in chapter 3. The reason for that is this project, amongst other things, serves as a test bed for trying out new ideas and concepts. Sometimes they work, sometimes they don't, but the end result is that it won't necessarily match precisely what is described in the book I co-authored. +For pyup.io Users +----------------- + +If you are using `pyup.io`_ to keep your dependencies updated and secure, use the code *cookiecutter* during checkout to get 15% off every month. + +.. _`pyup.io`: https://pyup.io + "Your Stuff" ------------- @@ -252,10 +263,26 @@ Support This Project This project is maintained by volunteers. Support their efforts by spreading the word about: -.. image:: https://s3.amazonaws.com/tsacademy/images/tsa-logo-250x60-transparent-01.png - :name: Two Scoops Academy +Two Scoops of Django 1.11 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: https://cdn.shopify.com/s/files/1/0304/6901/files/tsd-111-alpha-470x235.jpg?2934688328290951771 + :name: Two Scoops of Django 1.11 Cover :align: center - :alt: Two Scoops Academy - :target: https://twoscoops.academy/ + :alt: Two Scoops of Django + :target: http://twoscoopspress.org/products/two-scoops-of-django-1-11 + +Two Scoops of Django is the best dairy-themed Django reference in the universe + +pyup +~~~~~~~~~~~~~~~~~~ + +.. image:: https://pyup.io/static/images/logo.png + :name: pyup + :align: center + :alt: pyup + :target: https://pyup.io/ + +Pyup brings you automated security and dependency updates used by Google and other organizations. Free for open source projects! .. _`PyPA Code of Conduct`: https://www.pypa.io/en/latest/code-of-conduct/ diff --git a/cookiecutter.json b/cookiecutter.json index 9b9c67077..4450e6933 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -14,11 +14,11 @@ "use_opbeat": "n", "use_pycharm": "n", "windows": "n", - "use_python3": "y", - "use_docker": "y", + "use_docker": "n", "use_heroku": "n", + "use_elasticbeanstalk_experimental": "n", "use_compressor": "n", - "postgresql_version": ["9.5", "9.4", "9.3", "9.2"], + "postgresql_version": ["9.6", "9.5", "9.4", "9.3", "9.2"], "js_task_runner": ["Gulp", "Grunt", "None"], "use_lets_encrypt": "n", "open_source_license": ["MIT", "BSD", "GPLv3", "Apache Software License 2.0", "Not open source"] diff --git a/docs/conf.py b/docs/conf.py index 293d0fc14..f8810ca7a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # cookiecutter-django documentation build configuration file. # # This file is execfile()d with the current directory set to its containing dir. @@ -10,8 +8,6 @@ # All configuration values have a default; values that are commented out # serve to show the default. -from __future__ import unicode_literals - from datetime import datetime import os import sys diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index 5b9b4a2c4..b84edfa46 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -3,7 +3,7 @@ Deployment on Heroku .. index:: Heroku -You can either push the 'deploy' button in your generated README.rst or run these commands to deploy the project to Heroku: +Run these commands to deploy the project to Heroku: .. code-block:: bash @@ -27,9 +27,10 @@ You can either push the 'deploy' button in your generated README.rst or run thes heroku config:set DJANGO_MAILGUN_SERVER_NAME=YOUR_MALGUN_SERVER heroku config:set DJANGO_MAILGUN_API_KEY=YOUR_MAILGUN_API_KEY + heroku config:set MAILGUN_SENDER_DOMAIN=YOUR_MAILGUN_SENDER_DOMAIN heroku config:set PYTHONHASHSEED=random - heroku config:set DJANGO_ADMIN_URL=\^somelocation/ + heroku config:set DJANGO_ADMIN_URL=\^somelocation/ git push heroku master heroku run python manage.py migrate diff --git a/docs/deployment-on-pythonanywhere.rst b/docs/deployment-on-pythonanywhere.rst index 6aacba154..07b46bc05 100644 --- a/docs/deployment-on-pythonanywhere.rst +++ b/docs/deployment-on-pythonanywhere.rst @@ -35,7 +35,7 @@ Make sure your project is fully commited and pushed up to Bitbucket or Github or git clone # you can also use hg cd my-project-name - mkvirtualenv --python=/usr/bin/python3.5 my-project-name # or python2.7, etc + mkvirtualenv --python=/usr/bin/python3.5 my-project-name pip install -r requirements/production.txt # may take a few minutes @@ -47,7 +47,7 @@ Generate a secret key for yourself, eg like this: .. code-block:: bash - python -c 'import random; print("".join(random.SystemRandom().choice("abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)") for _ in range(50)))' + python -c 'import random;import string; print("".join(random.SystemRandom().choice(string.digits + string.ascii_letters + string.punctuation) for _ in range(50)))' Make a note of it, since we'll need it here in the console and later on in the web app config tab. @@ -69,6 +69,7 @@ Add these exports export DJANGO_ADMIN_URL='' export DJANGO_MAILGUN_API_KEY='' export DJANGO_MAILGUN_SERVER_NAME='' + export MAILGUN_SENDER_DOMAIN='' export DJANGO_AWS_ACCESS_KEY_ID= export DJANGO_AWS_SECRET_ACCESS_KEY= export DJANGO_AWS_STORAGE_BUCKET_NAME= @@ -84,7 +85,7 @@ Go to the PythonAnywhere **Databases tab** and configure your database. * For Postgres, setup your superuser password, then open a Postgres console and run a `CREATE DATABASE my-db-name`. You should probably also set up a specific role and permissions for your app, rather than using the superuser credentials. Make a note of the address and port of your postgres server. -* For MySQL, set the password and create a database. More info here: https://help.pythonanywhere.com/pages/UsingMySQL +* For MySQL, set the password and create a database. More info here: https://help.pythonanywhere.com/pages/UsingMySQL * You can also use sqlite if you like! Not recommended for anything beyond toy projects though. @@ -139,6 +140,7 @@ Click through to the **WSGI configuration file** link (near the top) and edit th os.environ['DJANGO_ADMIN_URL'] = '' os.environ['DJANGO_MAILGUN_API_KEY'] = '' os.environ['DJANGO_MAILGUN_SERVER_NAME'] = '' + os.environ['MAILGUN_SENDER_DOMAIN'] = '' os.environ['DJANGO_AWS_ACCESS_KEY_ID'] = '' os.environ['DJANGO_AWS_SECRET_ACCESS_KEY'] = '' os.environ['DJANGO_AWS_STORAGE_BUCKET_NAME'] = '' @@ -178,5 +180,3 @@ For subsequent deployments, the procedure is much simpler. In a Bash console: And then go to the Web tab and hit **Reload** **TIP:** *if you're really keen, you can set up git-push based deployments: https://blog.pythonanywhere.com/87/* - - diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index 03aefd486..ac4af6e0c 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -37,6 +37,26 @@ root directory of this project as a starting point. Add your own variables to th file won't be tracked by git by default so you'll have to make sure to use some other mechanism to copy your secret if you are relying solely on git. +To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with `sentry.io`_), and set the `DJANGO_SENTRY_DSN` variable. This should be enough to report crashes to Sentry. + +You will probably also need to setup the Mail backend, for example by adding a `Mailgun`_ API key and a `Mailgun`_ sender domain, otherwise, the account creation view will crash and result in a 500 error when the backend attempts to send an email to the account owner. + +.. _sentry.io: https://sentry.io/welcome +.. _Mailgun: https://mailgun.com + +HTTPS is on by default +---------------------- + +SSL (Secure Sockets Layer) is a standard security technology for establishing an encrypted link between a server and a client, typically in this case, a web server (website) and a browser. Not having HTTPS means that malicious network users can sniff authentication credentials between your website and end users' browser. + +It is always better to deploy a site behind HTTPS and will become crucial as the web services extend to the IoT (Internet of Things). For this reason, we have set up a number of security defaults to help make your website secure: + +* In the `.env.example`, we have made it simpler for you to change the default `Django Admin` into a custom name through an environmental variable. This should make it harder to guess the access to the admin panel. + +* If you are not using a subdomain of the domain name set in the project, then remember to put the your staging/production IP address in the ``ALLOWED_HOSTS``_ environment variable before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol. + +* Access to the Django admin is set up by default to require HTTPS in production or once *live*. We recommend that you look into setting up the *Certbot and Let's Encrypt Setup* mentioned below or another HTTPS certification service. + Optional: nginx-proxy Setup --------------------------- @@ -52,8 +72,7 @@ This pass all incoming requests on `nginx-proxy`_ to the nginx service your appl Optional: Postgres Data Volume Modifications --------------------------------------------- -Postgres is saving its database files to the `postgres_data` volume by default. Change that if you wan't -something else and make sure to make backups since this is not done automatically. +Postgres is saving its database files to the `postgres_data` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically. Optional: Certbot and Let's Encrypt Setup ------------------------------------------ @@ -90,7 +109,7 @@ If you would like to set up autorenewal of your certificates, the following comm #!/bin/bash cd docker-compose run --rm --name certbot certbot bash -c "sleep 6 && certbot certonly --standalone -d {{ cookiecutter.domain_name }} --text --agree-tos --email {{ cookiecutter.email }} --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01" - docker exec pearl_nginx_1 nginx -s reload + docker exec {{ cookiecutter.project_name }}_nginx_1 nginx -s reload And then set a cronjob by running `crontab -e` and placing in it (period can be adjusted as desired):: @@ -143,7 +162,7 @@ If you have errors, you can always check your stack with `docker-compose`. Switc Supervisor Example ------------------- -Once you are ready with your initial setup, you wan't to make sure that your application is run by a process manager to +Once you are ready with your initial setup, you want to make sure that your application is run by a process manager to survive reboots and auto restarts in case of an error. You can use the process manager you are most familiar with. All it needs to do is to run `docker-compose up` in your projects root directory. diff --git a/docs/deployment-with-elastic-beanstalk.rst b/docs/deployment-with-elastic-beanstalk.rst new file mode 100644 index 000000000..e8aae8853 --- /dev/null +++ b/docs/deployment-with-elastic-beanstalk.rst @@ -0,0 +1,72 @@ +Deployment with Elastic Beanstalk +========================================== + +.. index:: Elastic Beanstalk + +Warning: Experimental +--------------------- + +This is experimental. For the time being there will be bugs and issues. If you've never used Elastic Beanstalk before, please hold off before trying this option. + +On the other hand, we need help cleaning this up. If you do have knowledge of Elastic Beanstalk, we would appreciate the help. :) + +Prerequisites +------------- + +* awsebcli + +Instructions +------------- + +If you haven't done so, create a directory of environments:: + + eb init -p python3.4 MY_PROJECT_SLUG + +Replace `MY_PROJECT_SLUG` with the value you entered for `project_slug`. + +Once that is done, create the environment (server) where the app will run:: + + eb create MY_PROJECT_SLUG + # Note: This will eventually fail on a postgres error, because postgres doesn't exist yet + +Now make sure you are in the right environment:: + + eb list + +If you are not in the right environment, then put yourself in the correct one:: + + eb use MY_PROJECT_SLUG + +Set the environment variables. Notes: You will be prompted if the `.env` file is missing. The script will ignore any PostgreSQL values, as RDS uses it's own system:: + + # Set the environment variables + python ebsetenv.py + +Speaking of PostgreSQL, go to the Elasting Beanstalk configuration panel for RDS. Create new RDS database, with these attributes: + +* PostgreSQL +* Version 9.4.9 +* Size db.t2.micro (You can upgrade later) + +(Get some coffee, this is going to take a while) + +Once you have a database specified, deploy again so your instance can pick up the new PostgreSQL values:: + + eb deploy + +Take a look:: + + eb open + +FAQ +----- + +Why Not Use Docker on Elastic Beanstalk? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Because I didn't want to add an abstraction (Docker) on top of an abstraction (Elastic Beanstalk) on top of an abstraction (Cookiecutter Django). + +Why Can't I Use Both Docker/Heroku with Elastic Beanstalk? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Because the environment variables that our Docker and Heroku setups use for PostgreSQL access is different then how Amazon RDS handles this access. At this time we're just trying to get things to work reliably with Elastic Beanstalk, and full integration will come later. diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 65312e8d7..19c24f8e5 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -20,6 +20,16 @@ If you don't already have it installed, follow the instructions for your OS: .. _`Docker for Windows`: https://docs.docker.com/engine/installation/windows/ .. _`docker-engine`: https://docs.docker.com/engine/installation/ +Attention Windows users +------------- + +Currently PostgreSQL (``psycopg2`` python package) is not installed inside Docker containers for Windows users, while it is required by the generated Django project. To fix this, add ``psycopg2`` to the list of requirements inside ``requirements/base.txt``:: + + # Python-PostgreSQL Database Adapter + psycopg2==2.6.2 + +Doing this will prevent the project from being installed in an Windows-only environment (thus without usage of Docker). If you want to use this project without Docker, make sure to remove ``psycopg2`` from the requirements again. + Build the Stack --------------- @@ -63,6 +73,11 @@ To migrate your app and to create a superuser, run:: Here we specify the ``django`` container as the location to run our management commands. +Add your Docker development server IP +------------------------------------ + +When ``DEBUG`` is set to `True`, the host is validated against ``['localhost', '127.0.0.1', '[::1]']``. This is adequate when running a ``virtualenv``. For Docker, in the ``config.settings.local``, add your host development server IP to ``INTERNAL_IPS`` or ``ALLOWED_HOSTS`` if the variable exists. + Production Mode ~~~~~~~~~~~~~~~ diff --git a/docs/developing-locally.rst b/docs/developing-locally.rst index 6c84ca3c2..8aae8f0bd 100644 --- a/docs/developing-locally.rst +++ b/docs/developing-locally.rst @@ -50,7 +50,7 @@ Setup your email backend django-allauth sends an email to verify users (and superusers) after signup and login (if they are still not verified). To send email you need to `configure your email backend`_ -.. _configure your email backend: http://docs.djangoproject.com/en/1.9/topics/email/#smtp-backend +.. _configure your email backend: https://docs.djangoproject.com/en/dev/topics/email/#smtp-backend In development you can (optionally) use MailHog_ for email testing. MailHog is built with Go so there are no dependencies. To use MailHog: diff --git a/docs/faq.rst b/docs/faq.rst index 854e9dddd..def4ba1f9 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -8,9 +8,9 @@ Why is there a django.contrib.sites directory in Cookiecutter Django? It is there to add a migration so you don't have to manually change the ``sites.Site`` record from ``example.com`` to whatever your domain is. Instead, your ``{{cookiecutter.domain_name}}`` and {{cookiecutter.project_name}} value is placed by **Cookiecutter** in the domain and name fields respectively. -See `0002_set_site_domain_and_name.py`_. +See `0003_set_site_domain_and_name.py`_. -.. _`0002_set_site_domain_and_name.py`: https://github.com/pydanny/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/contrib/sites/migrations/0002_set_site_domain_and_name.py +.. _`0003_set_site_domain_and_name.py`: https://github.com/pydanny/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/contrib/sites/migrations/0003_set_site_domain_and_name.py Why aren't you using just one configuration file (12-Factor App) diff --git a/docs/index.rst b/docs/index.rst index 07cedc4ab..bfa88f18c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -25,6 +25,7 @@ Contents: faq troubleshooting my-favorite-cookie + deployment-with-elastic-beanstalk Indices and tables ================== diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index c2b14e874..5ada6a3fa 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -25,7 +25,7 @@ version [0.1.0] The starting version number for your project. timezone [UTC] - Used in the common settings file for the `TIME_ZONE` value. + Used in the base settings file for the `TIME_ZONE` value. use_whitenoise [y] Whether to use WhiteNoise_ for static file serving. @@ -54,10 +54,6 @@ use_pycharm [n] windows [n] Whether you'll be developing on Windows. -use_python3 [y] - By default, the Python code generated will be for Python 3.x. But if you - answer `n` here, it will be legacy Python 2.7 code. - use_docker [y] Whether to use Docker_, separating the app and database into separate containers. @@ -74,8 +70,7 @@ js_task_runner [1] 1. Gulp_ 2. Grunt_ - 3. Webpack_ - 4. None + 3. None use_lets_encrypt [n] Use `Let's Encrypt`_ as the certificate authority for this project. diff --git a/docs/settings.rst b/docs/settings.rst index 768ff6182..893a47e90 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -3,7 +3,14 @@ Settings This project relies extensively on environment settings which **will not work with Apache/mod_wsgi setups**. It has been deployed successfully with both Gunicorn/Nginx and even uWSGI/Nginx. -For configuration purposes, the following table maps environment variables to their Django setting: +For configuration purposes, the following table maps environment variables to their Django setting and project settings: + + +======================================= =========================== ============================================== ====================================================================== +Environment Variable Django Setting Development Default Production Default +======================================= =========================== ============================================== ====================================================================== +DJANGO_READ_DOT_ENV_FILE READ_DOT_ENV_FILE False False +======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ====================================================================== @@ -40,6 +47,7 @@ DJANGO_SENTRY_CLIENT SENTRY_CLIENT n/a DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO DJANGO_MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error DJANGO_MAILGUN_SERVER_NAME MAILGUN_SERVER_NAME n/a raises error +MAILGUN_SENDER_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error NEW_RELIC_APP_NAME NEW_RELIC_APP_NAME n/a raises error NEW_RELIC_LICENSE_KEY NEW_RELIC_LICENSE_KEY n/a raises error DJANGO_OPBEAT_APP_ID OPBEAT['APP_ID'] n/a raises error diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index dd6a3f07d..5e1eff9bd 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -12,10 +12,10 @@ A portion of this code was adopted from Django's standard crypto functions and utilities, specifically: https://github.com/django/django/blob/master/django/utils/crypto.py """ -from __future__ import print_function import os import random import shutil +import string # Get the root project directory PROJECT_DIRECTORY = os.path.realpath(os.path.curdir) @@ -28,16 +28,19 @@ except NotImplementedError: using_sysrandom = False -def get_random_string( - length=50, - allowed_chars='abcdefghijklmnopqrstuvwxyz0123456789!@#%^&*(-_=+)'): +def get_random_string(length=50): """ Returns a securely generated random string. The default length of 12 with the a-z, A-Z, 0-9 character set returns a 71-bit value. log_2((26+26+10)^12) =~ 71 bits """ + punctuation = string.punctuation.replace('"', '').replace("'", '') + punctuation = punctuation.replace('\\', '') if using_sysrandom: - return ''.join(random.choice(allowed_chars) for i in range(length)) + return ''.join(random.choice( + string.digits + string.ascii_letters + punctuation + ) for i in range(length)) + print( "Cookiecutter Django couldn't find a secure pseudo-random number generator on your system." " Please change change your SECRET_KEY variables in conf/settings/local.py and env.example" @@ -115,7 +118,10 @@ def remove_heroku_files(): """ Removes files needed for heroku if it isn't going to be used """ - for filename in ["app.json", "Procfile", "requirements.txt", "runtime.txt"]: + filenames = ["Procfile", "runtime.txt"] + if '{{ cookiecutter.use_elasticbeanstalk_experimental }}'.lower() != 'y': + filenames.append("requirements.txt") + for filename in ["Procfile", "runtime.txt"]: file_name = os.path.join(PROJECT_DIRECTORY, filename) remove_file(file_name) @@ -179,6 +185,32 @@ def remove_copying_files(): PROJECT_DIRECTORY, filename )) +def remove_elasticbeanstalk(): + """ + Removes elastic beanstalk components + """ + docs_dir_location = os.path.join(PROJECT_DIRECTORY, '.ebextensions') + if os.path.exists(docs_dir_location): + shutil.rmtree(docs_dir_location) + + filenames = ["ebsetenv.py", ] + if '{{ cookiecutter.use_heroku }}'.lower() != 'y': + filenames.append("requirements.txt") + for filename in filenames: + os.remove(os.path.join( + PROJECT_DIRECTORY, filename + )) + +def remove_open_source_files(): + """ + Removes files conventional to opensource projects only. + """ + for filename in ["CONTRIBUTORS.txt"]: + os.remove(os.path.join( + PROJECT_DIRECTORY, filename + )) + + # IN PROGRESS # def copy_doc_files(project_directory): # cookiecutters_dir = DEFAULT_CONFIG['cookiecutters_dir'] @@ -258,5 +290,10 @@ if '{{ cookiecutter.use_lets_encrypt }}'.lower() == 'y' and '{{ cookiecutter.use if '{{ cookiecutter.open_source_license}}' != 'GPLv3': remove_copying_files() -# 4. Copy files from /docs/ to {{ cookiecutter.project_slug }}/docs/ -# copy_doc_files(PROJECT_DIRECTORY) +# 12. Remove Elastic Beanstalk files +if '{{ cookiecutter.use_elasticbeanstalk_experimental }}'.lower() != 'y': + remove_elasticbeanstalk() + +# 13. Remove files conventional to opensource projects only. +if '{{ cookiecutter.open_source_license }}' == 'Not open source': + remove_open_source_files() \ No newline at end of file diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index 9cd168bce..c7a68450b 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -3,4 +3,29 @@ project_slug = '{{ cookiecutter.project_slug }}' if hasattr(project_slug, 'isidentifier'): assert project_slug.isidentifier(), 'Project slug should be valid Python identifier!' +elasticbeanstalk = '{{ cookiecutter.use_elasticbeanstalk_experimental }}'.lower() +heroku = '{{ cookiecutter.use_heroku }}'.lower() +docker = '{{ cookiecutter.use_docker }}'.lower() +if elasticbeanstalk == 'y' and (heroku == 'y' or docker == 'y'): + raise Exception("Cookiecutter Django's EXPERIMENTAL Elastic Beanstalk support is incompatible with Heroku and Docker setups.") + +if docker == 'n': + import sys + + python_major_version = sys.version_info[0] + + if python_major_version == 2: + sys.stdout.write("WARNING: Cookiecutter Django does not support Python 2! Stability is guaranteed with Python 3.4+ only. Are you sure you want to proceed? (y/n)") + + yes_options = set(['y']) + no_options = set(['n', '']) + choice = raw_input().lower() + if choice in no_options: + sys.exit(1) + elif choice in yes_options: + pass + else: + sys.stdout.write("Please respond with %s or %s" + % (', '.join([o for o in yes_options if not o == '']) + , ', '.join([o for o in no_options if not o == '']))) diff --git a/requirements.txt b/requirements.txt index c0665d454..ebc618046 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,11 @@ -cookiecutter==1.4.0 -flake8==3.0.4 # pyup: != 2.6.0 -sh==1.11 -binaryornot==0.4.0 +cookiecutter==1.5.1 +flake8==3.3.0 # pyup: != 2.6.0 +sh==1.12.13 +binaryornot==0.4.3 # Testing -pytest==3.0.2 +pytest==3.0.7 pep8==1.7.0 -pyflakes==1.3.0 -tox==2.3.1 +pyflakes==1.5.0 +tox==2.7.0 pytest-cookies==0.2.0 diff --git a/requirements_to_watch.txt b/requirements_to_watch.txt index 3e25cb204..4440448d4 100644 --- a/requirements_to_watch.txt +++ b/requirements_to_watch.txt @@ -1,2 +1,4 @@ # These requirements prevented an upgrade to Django 1.10. -django-coverage-plugin==1.3.1 +django-coverage-plugin==1.5.0 +django-autoslug==1.9.3 + diff --git a/setup.cfg b/setup.cfg index c5b301991..140796cff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,3 @@ -[pytest] +[tool:pytest] python_paths = . norecursedirs = .tox .git */migrations/* */static/* docs venv */{{cookiecutter.project_slug}}/* diff --git a/setup.py b/setup.py index 35685f3bc..6dc6635ea 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ except ImportError: # Our version ALWAYS matches the version of Django we support # If Django has a new release, we branch, tag, then update this setting after the tag. -version = '1.9.9-04' +version = '1.10.7' if sys.argv[-1] == 'tag': os.system('git tag -a %s -m "version %s"' % (version, version)) @@ -34,13 +34,11 @@ setup( classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', - 'Framework :: Django :: 1.9', + 'Framework :: Django :: 1.10', 'Intended Audience :: Developers', 'Natural Language :: English', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py old mode 100644 new mode 100755 index e0e06ce6a..acbc2c09b --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import os import re import sh diff --git a/tests/test_docker.sh b/tests/test_docker.sh old mode 100644 new mode 100755 index 30a27dad3..3c047f0a3 --- a/tests/test_docker.sh +++ b/tests/test_docker.sh @@ -11,8 +11,11 @@ mkdir -p .cache/docker cd .cache/docker # create the project using the default settings in cookiecutter.json -cookiecutter ../../ --no-input --overwrite-if-exists +cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y js_task_runner=None cd project_name # run the project's tests docker-compose -f dev.yml run django python manage.py test + +# return non-zero status code if there are migrations that have not been created +docker-compose -f dev.yml run django python manage.py makemigrations --dry-run --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; } diff --git a/tox.ini b/tox.ini index d2cfed18c..311d80f45 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] skipsdist = true -envlist = py27,py34,py35 +envlist = py34,py35 [testenv] passenv = LC_ALL, LANG, HOME diff --git a/{{cookiecutter.project_slug}}/.ebextensions/10_packages.config b/{{cookiecutter.project_slug}}/.ebextensions/10_packages.config new file mode 100644 index 000000000..c0774efae --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/10_packages.config @@ -0,0 +1,5 @@ +packages: + yum: + git: [] + postgresql94-devel: [] + libjpeg-turbo-devel: [] diff --git a/{{cookiecutter.project_slug}}/.ebextensions/20_elasticcache.config b/{{cookiecutter.project_slug}}/.ebextensions/20_elasticcache.config new file mode 100644 index 000000000..26c059e30 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/20_elasticcache.config @@ -0,0 +1,46 @@ +#This sample requires you to create a separate configuration file that defines the custom +# option settings for CacheCluster properties. + +Resources: + MyCacheSecurityGroup: + Type: "AWS::EC2::SecurityGroup" + Properties: + GroupDescription: "Lock cache down to webserver access only" + SecurityGroupIngress : + - IpProtocol : "tcp" + FromPort : + Fn::GetOptionSetting: + OptionName : "CachePort" + DefaultValue: "6379" + ToPort : + Fn::GetOptionSetting: + OptionName : "CachePort" + DefaultValue: "6379" + SourceSecurityGroupName: + Ref: "AWSEBSecurityGroup" + MyElastiCache: + Type: "AWS::ElastiCache::CacheCluster" + Properties: + CacheNodeType: + Fn::GetOptionSetting: + OptionName : "CacheNodeType" + DefaultValue : "cache.t2.micro" + NumCacheNodes: + Fn::GetOptionSetting: + OptionName : "NumCacheNodes" + DefaultValue : "1" + Engine: + Fn::GetOptionSetting: + OptionName : "Engine" + DefaultValue : "redis" + VpcSecurityGroupIds: + - + Fn::GetAtt: + - MyCacheSecurityGroup + - GroupId + +Outputs: + ElastiCache: + Description : "ID of ElastiCache Cache Cluster with Redis Engine" + Value : + Ref : "MyElastiCache" diff --git a/{{cookiecutter.project_slug}}/.ebextensions/30_options.config b/{{cookiecutter.project_slug}}/.ebextensions/30_options.config new file mode 100644 index 000000000..fefec489d --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/30_options.config @@ -0,0 +1,6 @@ +option_settings: + "aws:elasticbeanstalk:customoption": + CacheNodeType : cache.t2.micro + NumCacheNodes : 1 + Engine : redis + CachePort : 6379 diff --git a/{{cookiecutter.project_slug}}/.ebextensions/40_python.config b/{{cookiecutter.project_slug}}/.ebextensions/40_python.config new file mode 100644 index 000000000..111bf1ca8 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/40_python.config @@ -0,0 +1,17 @@ +container_commands: + 01_migrate: + command: "source /opt/python/run/venv/bin/activate && python manage.py migrate --noinput" + leader_only: True + 02_collectstatic: + command: "source /opt/python/run/venv/bin/activate && python manage.py collectstatic --noinput" +option_settings: + "aws:elasticbeanstalk:application:environment": + DJANGO_SETTINGS_MODULE: "config.settings.production" + REDIS_ENDPOINT_ADDRESS: '`{ "Fn::GetAtt" : [ "MyElastiCache", "RedisEndpoint.Address"]}`' + REDIS_PORT: '`{ "Fn::GetAtt" : [ "MyElastiCache", "RedisEndpoint.Port"]}`' + "aws:elasticbeanstalk:container:python": + WSGIPath: "config/wsgi.py" + NumProcesses: 3 + NumThreads: 20 + "aws:elasticbeanstalk:container:python:staticfiles": + "/static/": "www/static/" diff --git a/{{cookiecutter.project_slug}}/.ebextensions/50_apache.config b/{{cookiecutter.project_slug}}/.ebextensions/50_apache.config new file mode 100644 index 000000000..672cb625b --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/50_apache.config @@ -0,0 +1,3 @@ +container_commands: + 01_setup_apache: + command: "cp .ebextensions/enable_mod_deflate.conf /etc/httpd/conf.d/enable_mod_deflate.conf" diff --git a/{{cookiecutter.project_slug}}/.ebextensions/enable_mod_deflate.conf b/{{cookiecutter.project_slug}}/.ebextensions/enable_mod_deflate.conf new file mode 100644 index 000000000..7a77cc234 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/enable_mod_deflate.conf @@ -0,0 +1,25 @@ +# mod_deflate configuration + + # Restrict compression to these MIME types + AddOutputFilterByType DEFLATE text/plain + AddOutputFilterByType DEFLATE text/html + AddOutputFilterByType DEFLATE application/xhtml+xml + AddOutputFilterByType DEFLATE text/xml + AddOutputFilterByType DEFLATE application/xml + AddOutputFilterByType DEFLATE application/xml+rss + AddOutputFilterByType DEFLATE application/x-javascript + AddOutputFilterByType DEFLATE text/javascript + AddOutputFilterByType DEFLATE text/css + # Level of compression (Highest 9 - Lowest 1) + DeflateCompressionLevel 9 + # Netscape 4.x has some problems. + BrowserMatch ^Mozilla/4 gzip-only-text/html + # Netscape 4.06-4.08 have some more problems + BrowserMatch ^Mozilla/4\.0[678] no-gzip + # MSIE masquerades as Netscape, but it is fine + BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html + + # Make sure proxies don't deliver the wrong content + Header append Vary User-Agent env=!dont-vary + + diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index 01406c13a..6a0a3029e 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -75,6 +75,7 @@ node_modules/ mailhog {% endif %} -{% if cookiecutter.use_compressor == 'y' %} staticfiles/ -{% endif %} + +.cache/ + diff --git a/{{cookiecutter.project_slug}}/.idea/runConfigurations/Docker__tests___all.xml b/{{cookiecutter.project_slug}}/.idea/runConfigurations/Docker__tests___all.xml index 7ede8bfb5..02fba0797 100644 --- a/{{cookiecutter.project_slug}}/.idea/runConfigurations/Docker__tests___all.xml +++ b/{{cookiecutter.project_slug}}/.idea/runConfigurations/Docker__tests___all.xml @@ -4,7 +4,7 @@