diff --git a/.editorconfig b/.editorconfig index 585e2abce..261407067 100644 --- a/.editorconfig +++ b/.editorconfig @@ -21,3 +21,7 @@ trim_trailing_whitespace = false [Makefile] indent_style = tab + +[nginx.conf] +indent_style = space +indent_size = 2 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/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 652b7bd55..0611babf3 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -95,6 +95,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`_ @@ -115,9 +116,11 @@ Listed in alphabetical order. Peter Bittner `@bittner`_ Raphael Pierzina `@hackebrot`_ Raony Guimarães Corrêa `@raonyguimaraes`_ + René Muhl `@rm--`_ Roman Afanaskin `@siauPatrick`_ Roman Osipenko `@romanosipenko`_ Russell Davies + Sam Collins `@MightySCollins`_ stepmr `@stepmr`_ Sławek Ehlert `@slafs`_ Srinivas Nyayapati `@shireenrao`_ @@ -195,6 +198,7 @@ Listed in alphabetical order. .. _@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 .. _@show0k: https://github.com/show0k @@ -214,6 +218,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..2f5256edf 100644 --- a/README.rst +++ b/README.rst @@ -26,9 +26,9 @@ Powered by Cookiecutter_, Cookiecutter Django is a framework for jumpstarting pr Features --------- -* For Django 1.9 +* For Django 1.10 * Renders Django projects with 100% starting test coverage -* Twitter Bootstrap_ v4.0.0 - `alpha 3`_ +* Twitter Bootstrap_ v4.0.0 - `alpha 4`_ * 12-Factor_ based settings via django-environ_ * Optimized development and production settings * Registration via django-allauth_ @@ -42,6 +42,7 @@ Features * 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 Optional Integrations @@ -55,7 +56,7 @@ 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/ +.. _`alpha 4`: http://blog.getbootstrap.com/2016/09/05/bootstrap-4-alpha-4/ .. _Bootstrap: https://github.com/twbs/bootstrap .. _django-environ: https://github.com/joke2k/django-environ .. _12-Factor: http://12factor.net/ @@ -89,7 +90,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:: @@ -146,6 +147,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:: diff --git a/cookiecutter.json b/cookiecutter.json index 9b9c67077..bf729b678 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -17,6 +17,7 @@ "use_python3": "y", "use_docker": "y", "use_heroku": "n", + "use_elasticbeanstalk_experimental": "n", "use_compressor": "n", "postgresql_version": ["9.5", "9.4", "9.3", "9.2"], "js_task_runner": ["Gulp", "Grunt", "None"], diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index 5b9b4a2c4..843e230fb 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -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..82399eb15 100644 --- a/docs/deployment-on-pythonanywhere.rst +++ b/docs/deployment-on-pythonanywhere.rst @@ -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. 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/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/settings.rst b/docs/settings.rst index 768ff6182..eb6e92a45 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -40,6 +40,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..068d74831 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -115,7 +115,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 +182,22 @@ 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 + )) + # IN PROGRESS # def copy_doc_files(project_directory): # cookiecutters_dir = DEFAULT_CONFIG['cookiecutters_dir'] @@ -258,5 +277,6 @@ 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() diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index 9cd168bce..cd31774e0 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -3,4 +3,9 @@ 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.") diff --git a/requirements.txt b/requirements.txt index c0665d454..73e90f9a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,8 +4,8 @@ sh==1.11 binaryornot==0.4.0 # Testing -pytest==3.0.2 +pytest==3.0.3 pep8==1.7.0 pyflakes==1.3.0 -tox==2.3.1 +tox==2.4.1 pytest-cookies==0.2.0 diff --git a/requirements_to_watch.txt b/requirements_to_watch.txt index 3e25cb204..34f0fe621 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-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 469e173c7..a20a28b2b 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-03' +version = '1.10.1' if sys.argv[-1] == 'tag': os.system('git tag -a %s -m "version %s"' % (version, version)) @@ -34,7 +34,7 @@ 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', diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py old mode 100644 new mode 100755 diff --git a/tests/test_docker.sh b/tests/test_docker.sh old mode 100644 new mode 100755 index 30a27dad3..ced9b1829 --- a/tests/test_docker.sh +++ b/tests/test_docker.sh @@ -16,3 +16,6 @@ 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/{{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..539f55094 --- /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.t1.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..d7135c3f9 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.ebextensions/30_options.config @@ -0,0 +1,6 @@ +option_settings: + "aws:elasticbeanstalk:customoption": + CacheNodeType : cache.t1.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}}/.editorconfig b/{{cookiecutter.project_slug}}/.editorconfig index 9759b2ca6..b19266bf3 100644 --- a/{{cookiecutter.project_slug}}/.editorconfig +++ b/{{cookiecutter.project_slug}}/.editorconfig @@ -27,3 +27,7 @@ trim_trailing_whitespace = false [Makefile] indent_style = tab + +[nginx.conf] +indent_style = space +indent_size = 2 diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index f2d14296f..90ce80dce 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -24,8 +24,10 @@ sftp-config.json __pycache__ # Logs +logs *.log pip-log.txt +npm-debug.log* # Unit test / coverage reports .coverage @@ -68,9 +70,9 @@ node_modules/ # User-uploaded media {{ cookiecutter.project_slug }}/media/ -# Hitch directory -tests/.hitch -{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n'%} +{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %} # MailHog binary mailhog {% endif %} + +staticfiles/ diff --git a/{{cookiecutter.project_slug}}/README.rst b/{{cookiecutter.project_slug}}/README.rst index f760a1e2c..4640f2656 100644 --- a/{{cookiecutter.project_slug}}/README.rst +++ b/{{cookiecutter.project_slug}}/README.rst @@ -117,19 +117,16 @@ Deployment ---------- The following details how to deploy this application. -{% if cookiecutter.use_heroku == "y" %} +{% if cookiecutter.use_heroku.lower() == "y" %} Heroku ^^^^^^ -.. image:: https://www.herokucdn.com/deploy/button.png - :target: https://heroku.com/deploy - See detailed `cookiecutter-django Heroku documentation`_. .. _`cookiecutter-django Heroku documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-on-heroku.html {% endif %} -{% if cookiecutter.use_docker == "y" %} +{% if cookiecutter.use_docker.lower() == "y" %} Docker ^^^^^^ @@ -138,3 +135,13 @@ See detailed `cookiecutter-django Docker documentation`_. .. _`cookiecutter-django Docker documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html {% endif %} +{% if cookiecutter.use_elasticbeanstalk_experimental.lower() == 'y' %} + +Elastic Beanstalk +~~~~~~~~~~~~~~~~~~ + +See detailed `cookiecutter-django Elastic Beanstalk documentation`_. + +.. _`cookiecutter-django Docker documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-elastic-beanstalk.html + +{% endif %} diff --git a/{{cookiecutter.project_slug}}/app.json b/{{cookiecutter.project_slug}}/app.json deleted file mode 100644 index 96ab574f4..000000000 --- a/{{cookiecutter.project_slug}}/app.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "{{cookiecutter.project_slug}}", - "description": "{{cookiecutter.description}}", - "env": { - "BUILDPACK_URL": "https://github.com/heroku/heroku-buildpack-python", - "DJANGO_SETTINGS_MODULE": "config.settings.production", - "DJANGO_SECRET_KEY": { - "description": "A secret key for verifying the integrity of signed cookies.", - "generator": "secret" - }, - "DJANGO_ALLOWED_HOSTS": { - "description": "Comma-separated list of hosts", - "value": ".herokuapp.com" - }, - "DJANGO_ADMIN_URL": { - "description": "A secret URL for the Django admin", - "generator": "secret" - }, - "DJANGO_AWS_ACCESS_KEY_ID": "", - "DJANGO_AWS_SECRET_ACCESS_KEY": "", - "DJANGO_AWS_STORAGE_BUCKET_NAME": "", - "DJANGO_MAILGUN_SERVER_NAME": "", - "DJANGO_MAILGUN_API_KEY": ""{% if cookiecutter.use_sentry_for_error_reporting == "y" -%}, - "DJANGO_SENTRY_DSN": ""{%- endif %} - }, - "scripts": { - "postdeploy": "python manage.py migrate" - }, - "addons": [ - { - "plan": "heroku-postgresql:hobby-dev", - "options": { - "version": "{{ cookiecutter.postgresql_version }}" - } - }, - "heroku-redis:hobby-dev", - "mailgun" - ] -} diff --git a/{{cookiecutter.project_slug}}/compose/nginx/nginx.conf b/{{cookiecutter.project_slug}}/compose/nginx/nginx.conf index 5d7faa394..9573effef 100644 --- a/{{cookiecutter.project_slug}}/compose/nginx/nginx.conf +++ b/{{cookiecutter.project_slug}}/compose/nginx/nginx.conf @@ -4,67 +4,58 @@ worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; - events { - worker_connections 1024; + worker_connections 1024; } http { + include /etc/nginx/mime.types; + default_type application/octet-stream; - include /etc/nginx/mime.types; - default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; - access_log /var/log/nginx/access.log main; + sendfile on; + #tcp_nopush on; - sendfile on; - #tcp_nopush on; + keepalive_timeout 65; - keepalive_timeout 65; + #gzip on; - #gzip on; + upstream app { + server django:5000; + } - upstream app { - server django:5000; + server { + listen 80; + charset utf-8; + + {% if cookiecutter.use_lets_encrypt == 'y' and cookiecutter.use_docker == 'y' %} + server_name ___my.example.com___ ; + + location /.well-known/acme-challenge { + proxy_pass http://certbot:80; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto https; + } + {% endif %} + + location / { + # checks for static file, if not found proxy to app + try_files $uri @proxy_to_app; } - server { - listen 80; - charset utf-8; + # cookiecutter-django app + location @proxy_to_app { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_redirect off; + proxy_pass http://app; - {% if cookiecutter.use_lets_encrypt == 'y' and cookiecutter.use_docker == 'y' %} - server_name ___my.example.com___ ; - - location /.well-known/acme-challenge { - proxy_pass http://certbot:80; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto https; - } - - {% endif %} - - location / { - # checks for static file, if not found proxy to app - try_files $uri @proxy_to_app; - } - - - # cookiecutter-django app - location @proxy_to_app { - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_redirect off; - - proxy_pass http://app; - - } - } + } + } } - - - - diff --git a/{{cookiecutter.project_slug}}/config/settings/common.py b/{{cookiecutter.project_slug}}/config/settings/common.py index c9433416c..04998575f 100644 --- a/{{cookiecutter.project_slug}}/config/settings/common.py +++ b/{{cookiecutter.project_slug}}/config/settings/common.py @@ -53,7 +53,7 @@ INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS # MIDDLEWARE CONFIGURATION # ------------------------------------------------------------------------------ -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -200,6 +200,26 @@ ROOT_URLCONF = 'config.urls' # See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application WSGI_APPLICATION = 'config.wsgi.application' + +# PASSWORD VALIDATION +# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators +# ------------------------------------------------------------------------------ + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + # AUTHENTICATION CONFIGURATION # ------------------------------------------------------------------------------ AUTHENTICATION_BACKENDS = ( diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index ac7ad0589..d09823d78 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -52,7 +52,7 @@ CACHES = { # django-debug-toolbar # ------------------------------------------------------------------------------ -MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',) +MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',) INSTALLED_APPS += ('debug_toolbar', ) INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', ] diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 04a9426fd..7fa726f6d 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -42,11 +42,11 @@ INSTALLED_APPS += ('raven.contrib.django.raven_compat', ) # Use Whitenoise to serve static files # See: https://whitenoise.readthedocs.io/ WHITENOISE_MIDDLEWARE = ('whitenoise.middleware.WhiteNoiseMiddleware', ) -MIDDLEWARE_CLASSES = WHITENOISE_MIDDLEWARE + MIDDLEWARE_CLASSES +MIDDLEWARE = WHITENOISE_MIDDLEWARE + MIDDLEWARE {% endif %} {%- if cookiecutter.use_sentry_for_error_reporting == 'y' -%} RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware', ) -MIDDLEWARE_CLASSES = RAVEN_MIDDLEWARE + MIDDLEWARE_CLASSES +MIDDLEWARE = RAVEN_MIDDLEWARE + MIDDLEWARE {% endif %} {%- if cookiecutter.use_opbeat == 'y' -%} # opbeat integration @@ -57,9 +57,9 @@ OPBEAT = { 'APP_ID': env('DJANGO_OPBEAT_APP_ID'), 'SECRET_TOKEN': env('DJANGO_OPBEAT_SECRET_TOKEN') } -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'opbeat.contrib.django.middleware.OpbeatAPMMiddleware', -) + MIDDLEWARE_CLASSES +) + MIDDLEWARE {% endif %} # SECURITY CONFIGURATION @@ -163,6 +163,7 @@ SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) INSTALLED_APPS += ("anymail", ) ANYMAIL = { "MAILGUN_API_KEY": env('DJANGO_MAILGUN_API_KEY'), + "MAILGUN_SENDER_DOMAIN": env('MAILGUN_SENDER_DOMAIN') } EMAIL_BACKEND = "anymail.backends.mailgun.MailgunBackend" @@ -177,16 +178,39 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [ # DATABASE CONFIGURATION # ------------------------------------------------------------------------------ +{% if cookiecutter.use_elasticbeanstalk_experimental.lower() == 'y' -%} +# Uses Amazon RDS for database hosting, which doesn't follow the Heroku-style spec +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': env('RDS_DB_NAME'), + 'USER': env('RDS_USERNAME'), + 'PASSWORD': env('RDS_PASSWORD'), + 'HOST': env('RDS_HOSTNAME'), + 'PORT': env('RDS_PORT'), + } +} +{% else %} +# Use the Heroku-style specification # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ DATABASES['default'] = env.db('DATABASE_URL') +{%- endif %} # CACHING # ------------------------------------------------------------------------------ +{% if cookiecutter.use_elasticbeanstalk_experimental.lower() == 'y' -%} +REDIS_LOCATION = "redis://{}:{}/0".format( + env('REDIS_ENDPOINT_ADDRESS'), + env('REDIS_PORT') +) +{% else %} +REDIS_LOCATION = '{0}/{1}'.format(env('REDIS_URL', default='redis://127.0.0.1:6379'), 0) +{%- endif %} # Heroku URL does not pass the DB number, so we parse it in CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': '{0}/{1}'.format(env('REDIS_URL', default='redis://127.0.0.1:6379'), 0), + 'LOCATION': REDIS_LOCATION, 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', 'IGNORE_EXCEPTIONS': True, # mimics memcache behavior. diff --git a/{{cookiecutter.project_slug}}/config/urls.py b/{{cookiecutter.project_slug}}/config/urls.py index f3a621127..6bb25f745 100644 --- a/{{cookiecutter.project_slug}}/config/urls.py +++ b/{{cookiecutter.project_slug}}/config/urls.py @@ -13,7 +13,7 @@ urlpatterns = [ url(r'^about/$', TemplateView.as_view(template_name='pages/about.html'), name='about'), # Django Admin, use {% raw %}{% url 'admin:index' %}{% endraw %} - url(settings.ADMIN_URL, include(admin.site.urls)), + url(settings.ADMIN_URL, admin.site.urls), # User management url(r'^users/', include('{{ cookiecutter.project_slug }}.users.urls', namespace='users')), @@ -33,3 +33,9 @@ if settings.DEBUG: url(r'^404/$', default_views.page_not_found, kwargs={'exception': Exception('Page not Found')}), url(r'^500/$', default_views.server_error), ] + if 'debug_toolbar' in settings.INSTALLED_APPS: + import debug_toolbar + + urlpatterns += [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] diff --git a/{{cookiecutter.project_slug}}/ebsetenv.py b/{{cookiecutter.project_slug}}/ebsetenv.py new file mode 100644 index 000000000..ba9652db7 --- /dev/null +++ b/{{cookiecutter.project_slug}}/ebsetenv.py @@ -0,0 +1,37 @@ +"""Converts a .env file to Elastic Beanstalk environment variables""" + +import os +from sys import exit +from subprocess import check_call + +try: + import dotenv +except ImportError: + print("Please install the 'dotenv' library: 'pip install dotenv'") + exit() + +def main(): + if not os.path.exists('.env'): + print('ERROR!! .env file is missing!') + print("Please copy 'env.example' to '.env' and add appropriate values") + exit() + command = ['eb', 'setenv'] + failures = [] + for key, value in dotenv.Dotenv('.env').items(): + if key.startswith('POSTGRES'): + print('Skipping POSTGRES values - Amazon RDS provides these') + continue + if value: + command.append("{}={}".format(key, value)) + else: + failures.append(key) + if failures: + for failure in failures: + print("{} requires a value".format(failure)) + else: + print(' '.join(command)) + check_call(command) + + +if __name__ == '__main__': + main() diff --git a/{{cookiecutter.project_slug}}/env.example b/{{cookiecutter.project_slug}}/env.example index 95a6a1d96..66a3570d7 100644 --- a/{{cookiecutter.project_slug}}/env.example +++ b/{{cookiecutter.project_slug}}/env.example @@ -1,3 +1,4 @@ + # PostgreSQL POSTGRES_PASSWORD=mysecretpass POSTGRES_USER=postgresuser @@ -16,6 +17,7 @@ DJANGO_AWS_STORAGE_BUCKET_NAME= # Used with email DJANGO_MAILGUN_API_KEY= DJANGO_SERVER_EMAIL= +MAILGUN_SENDER_DOMAIN= # Security! Better to use DNS for this task, but you can use redirect DJANGO_SECURE_SSL_REDIRECT=False @@ -33,4 +35,4 @@ DJANGO_OPBEAT_SECRET_TOKEN {% endif %} {% if cookiecutter.use_compressor == 'y' -%} COMPRESS_ENABLED= -{% endif %} \ No newline at end of file +{% endif %} diff --git a/{{cookiecutter.project_slug}}/manage.py b/{{cookiecutter.project_slug}}/manage.py index b41522c7d..9de71376f 100755 --- a/{{cookiecutter.project_slug}}/manage.py +++ b/{{cookiecutter.project_slug}}/manage.py @@ -5,6 +5,19 @@ import sys if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local') - from django.core.management import execute_from_command_line - + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django # noqa + except ImportError: + 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?" + ) + raise execute_from_command_line(sys.argv) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index fcc10ba24..ec567c465 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -7,28 +7,28 @@ wheel==0.29.0 {%- endif %} # Bleeding edge Django -django==1.9.9 +django==1.10.2 # Configuration django-environ==0.4.0 {% if cookiecutter.use_whitenoise == 'y' -%} -whitenoise==3.2.1 +whitenoise==3.2.2 {%- endif %} # Forms django-braces==1.9.0 -django-crispy-forms==1.6.0 +django-crispy-forms==1.6.1 # Models -django-model-utils==2.5.2 +django-model-utils==2.6 # Images -Pillow==3.3.1 +Pillow==3.4.1 # For user registration, either via email or social # Well-built with regular release cycles! -django-allauth==0.27.0 +django-allauth==0.28.0 {% if cookiecutter.windows == 'y' -%} # On Windows, you must download/install psycopg2 manually @@ -40,17 +40,16 @@ psycopg2==2.6.2 # Unicode slugification awesome-slugify==1.6.5 -django-autoslug==1.9.3 # Time zones support -pytz==2016.6.1 +pytz==2016.7 # Redis support -django-redis==4.4.4 -redis>=2.10.0 +django-redis==4.5.0 +redis>=2.10.5 {% if cookiecutter.use_celery == "y" %} -celery==3.1.23 +celery==3.1.24 {% endif %} {% if cookiecutter.use_compressor == "y" %} diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index bc260ba51..e563cb30c 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -2,15 +2,16 @@ -r base.txt coverage==4.2 django-coverage-plugin==1.3.1 -Sphinx==1.4.5 +Sphinx==1.4.8 django-extensions==1.7.4 Werkzeug==0.11.11 django-test-plus==1.0.15 factory_boy==2.7.0 -django-debug-toolbar==1.5 + +django-debug-toolbar==1.6 # improved REPL ipdb==0.10.1 -pytest-django==2.9.1 +pytest-django==3.0.0 pytest-sugar==0.7.1 diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index f0fbc1cb4..827f3eeb8 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -24,12 +24,12 @@ Collectfast==0.2.3 # Email backends for Mailgun, Postmark, SendGrid and more # ------------------------------------------------------- -django-anymail==0.4.2 +django-anymail==0.5 {% if cookiecutter.use_sentry_for_error_reporting == "y" -%} # Raven is the Sentry client # -------------------------- -raven==5.26.0 +raven==5.27.1 {%- endif %} {% if cookiecutter.use_opbeat == "y" -%} diff --git a/{{cookiecutter.project_slug}}/requirements/test.txt b/{{cookiecutter.project_slug}}/requirements/test.txt index b607cbc54..42ed08c56 100644 --- a/{{cookiecutter.project_slug}}/requirements/test.txt +++ b/{{cookiecutter.project_slug}}/requirements/test.txt @@ -13,5 +13,5 @@ django-test-plus==1.0.15 factory_boy==2.7.0 # pytest -pytest-django==2.9.1 +pytest-django==3.0.0 pytest-sugar==0.7.1 diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py index 555d02c42..b1803682a 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py @@ -1,31 +1,34 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import models, migrations import django.contrib.sites.models +from django.contrib.sites.models import _simple_domain_name_validator +from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( name='Site', fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('domain', models.CharField(verbose_name='domain name', max_length=100, validators=[django.contrib.sites.models._simple_domain_name_validator])), - ('name', models.CharField(verbose_name='display name', max_length=50)), + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('domain', models.CharField( + max_length=100, verbose_name='domain name', validators=[_simple_domain_name_validator] + )), + ('name', models.CharField(max_length=50, verbose_name='display name')), ], options={ - 'verbose_name_plural': 'sites', - 'verbose_name': 'site', - 'db_table': 'django_site', 'ordering': ('domain',), + 'db_table': 'django_site', + 'verbose_name': 'site', + 'verbose_name_plural': 'sites', }, + bases=(models.Model,), managers=[ - (b'objects', django.contrib.sites.models.SiteManager()), + ('objects', django.contrib.sites.models.SiteManager()), ], ), ] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py new file mode 100644 index 000000000..468718cde --- /dev/null +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import django.contrib.sites.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='site', + name='domain', + field=models.CharField( + max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator], + verbose_name='domain name' + ), + ), + ] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_set_site_domain_and_name.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py similarity index 96% rename from {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_set_site_domain_and_name.py rename to {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py index e6292f0b0..348989e13 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_set_site_domain_and_name.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py @@ -38,7 +38,7 @@ def update_site_backward(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('sites', '0001_initial'), + ('sites', '0002_alter_domain_unique'), ] operations = [ diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html new file mode 100644 index 000000000..c02bd4e9e --- /dev/null +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html @@ -0,0 +1,9 @@ +{% raw %}{% extends "base.html" %} + +{% block title %}Forbidden (403){% endblock %} + +{% block content %} +

Forbidden (403)

+ +

CSRF verification failed. Request aborted.

+{% endblock content %}{% endraw %} diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html index 64ddaa418..e816a208d 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html @@ -14,8 +14,8 @@ {% block css %} - - + + {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %} @@ -53,7 +53,7 @@ {% trans "My Profile" %} {% else %}