mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-07-04 20:33:07 +03:00
Merge branch 'master' of github.com:sfdye/cookiecutter-django into use-aws-roles
This commit is contained in:
commit
39d2000856
|
@ -2,6 +2,10 @@
|
||||||
All enhancements and patches to Cookiecutter Django will be documented in this file.
|
All enhancements and patches to Cookiecutter Django will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [2018-02-16]
|
||||||
|
### Changed
|
||||||
|
- Upgraded to Django 2.0 (@epicwhale)
|
||||||
|
|
||||||
## [2018-01-15]
|
## [2018-01-15]
|
||||||
### Changed
|
### Changed
|
||||||
- Removed Elastic Beanstalk support (@pydanny)
|
- Removed Elastic Beanstalk support (@pydanny)
|
||||||
|
|
|
@ -36,13 +36,12 @@ To run all tests using various versions of python in virtualenvs defined in tox.
|
||||||
|
|
||||||
$ tox
|
$ tox
|
||||||
|
|
||||||
It is possible to tests with some versions of python, to do this the command
|
It is possible to test with a specific version of python. To do this, the command
|
||||||
is::
|
is::
|
||||||
|
|
||||||
$ tox -e py34,py35
|
$ tox -e py36
|
||||||
|
|
||||||
Will run py.test with the python3.4, and python3.5 interpreters, for
|
This will run py.test with the python3.6 interpreter, for example.
|
||||||
example.
|
|
||||||
|
|
||||||
To run a particular test with tox for against your current Python version::
|
To run a particular test with tox for against your current Python version::
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,10 @@ production-ready Django projects quickly.
|
||||||
Features
|
Features
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* For Django 1.11
|
* For Django 2.0
|
||||||
* Works with Python 3.6
|
* Works with Python 3.6
|
||||||
* Renders Django projects with 100% starting test coverage
|
* Renders Django projects with 100% starting test coverage
|
||||||
* Twitter Bootstrap_ v4.0.0 - beta 1 (`maintained Foundation fork`_ also available)
|
* Twitter Bootstrap_ v4.0.0 (`maintained Foundation fork`_ also available)
|
||||||
* 12-Factor_ based settings via django-environ_
|
* 12-Factor_ based settings via django-environ_
|
||||||
* Secure by default. We believe in SSL.
|
* Secure by default. We believe in SSL.
|
||||||
* Optimized development and production settings
|
* Optimized development and production settings
|
||||||
|
@ -111,7 +111,7 @@ Two Scoops of Django 1.11
|
||||||
:name: Two Scoops of Django 1.11 Cover
|
:name: Two Scoops of Django 1.11 Cover
|
||||||
:align: center
|
:align: center
|
||||||
:alt: Two Scoops of Django
|
:alt: Two Scoops of Django
|
||||||
:target: http://twoscoopspress.org/products/two-scoops-of-django-1-11
|
:target: http://twoscoopspress.com/products/two-scoops-of-django-1-11
|
||||||
|
|
||||||
Two Scoops of Django is the best dessert-themed Django reference in the universe
|
Two Scoops of Django is the best dessert-themed Django reference in the universe
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ Make sure your project is fully commited and pushed up to Bitbucket or Github or
|
||||||
|
|
||||||
git clone <my-repo-url> # you can also use hg
|
git clone <my-repo-url> # you can also use hg
|
||||||
cd my-project-name
|
cd my-project-name
|
||||||
mkvirtualenv --python=/usr/bin/python3.5 my-project-name
|
mkvirtualenv --python=/usr/bin/python3.6 my-project-name
|
||||||
pip install -r requirements/production.txt # may take a few minutes
|
pip install -r requirements/production.txt # may take a few minutes
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ DJANGO_ADMIN_URL n/a r'^admin/'
|
||||||
DJANGO_CACHES CACHES (default) locmem redis
|
DJANGO_CACHES CACHES (default) locmem redis
|
||||||
DJANGO_DATABASES DATABASES (default) See code See code
|
DJANGO_DATABASES DATABASES (default) See code See code
|
||||||
DJANGO_DEBUG DEBUG True False
|
DJANGO_DEBUG DEBUG True False
|
||||||
DJANGO_SECRET_KEY SECRET_KEY CHANGEME!!! raises error
|
DJANGO_SECRET_KEY SECRET_KEY !!!SET DJANGO_SECRET_KEY!!! raises error
|
||||||
DJANGO_SECURE_BROWSER_XSS_FILTER SECURE_BROWSER_XSS_FILTER n/a True
|
DJANGO_SECURE_BROWSER_XSS_FILTER SECURE_BROWSER_XSS_FILTER n/a True
|
||||||
DJANGO_SECURE_SSL_REDIRECT SECURE_SSL_REDIRECT n/a True
|
DJANGO_SECURE_SSL_REDIRECT SECURE_SSL_REDIRECT n/a True
|
||||||
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF SECURE_CONTENT_TYPE_NOSNIFF n/a True
|
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF SECURE_CONTENT_TYPE_NOSNIFF n/a True
|
||||||
|
|
|
@ -1,219 +1,257 @@
|
||||||
"""
|
"""
|
||||||
Does the following:
|
NOTE:
|
||||||
|
the below code is to be maintained Python 2.x-compatible
|
||||||
|
as the whole Cookiecutter Django project initialization
|
||||||
|
can potentially be run in Python 2.x environment
|
||||||
|
(at least so we presume in `pre_gen_project.py`).
|
||||||
|
|
||||||
1. Generates and saves random secret key
|
TODO: ? restrict Cookiecutter Django project initialization to Python 3.x environments only
|
||||||
2. Removes the taskapp if celery isn't going to be used
|
|
||||||
3. Removes the .idea directory if PyCharm isn't going to be used
|
|
||||||
4. Copy files from /docs/ to {{ cookiecutter.project_slug }}/docs/
|
|
||||||
|
|
||||||
TODO: this might have to be moved to a pre_gen_hook
|
|
||||||
|
|
||||||
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 os
|
||||||
import random
|
import random
|
||||||
import shutil
|
import shutil
|
||||||
import string
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
# Get the root project directory
|
|
||||||
PROJECT_DIRECTORY = os.path.realpath(os.path.curdir)
|
|
||||||
|
|
||||||
# Use the system PRNG if possible
|
|
||||||
try:
|
try:
|
||||||
|
# Inspired by
|
||||||
|
# https://github.com/django/django/blob/master/django/utils/crypto.py
|
||||||
random = random.SystemRandom()
|
random = random.SystemRandom()
|
||||||
using_sysrandom = True
|
using_sysrandom = True
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
using_sysrandom = False
|
using_sysrandom = False
|
||||||
|
|
||||||
|
PROJECT_DIR_PATH = os.path.realpath(os.path.curdir)
|
||||||
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(
|
|
||||||
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"
|
|
||||||
" manually."
|
|
||||||
)
|
|
||||||
return "CHANGEME!!"
|
|
||||||
|
|
||||||
|
|
||||||
def set_secret_key(setting_file_location):
|
def remove_file(file_path):
|
||||||
# Open locals.py
|
if os.path.exists(file_path):
|
||||||
with open(setting_file_location) as f:
|
os.remove(file_path)
|
||||||
file_ = f.read()
|
|
||||||
|
|
||||||
# Generate a SECRET_KEY that matches the Django standard
|
|
||||||
SECRET_KEY = get_random_string()
|
|
||||||
|
|
||||||
# Replace "CHANGEME!!!" with SECRET_KEY
|
|
||||||
file_ = file_.replace('CHANGEME!!!', SECRET_KEY, 1)
|
|
||||||
|
|
||||||
# Write the results to the locals.py module
|
|
||||||
with open(setting_file_location, 'w') as f:
|
|
||||||
f.write(file_)
|
|
||||||
|
|
||||||
|
|
||||||
def make_secret_key(project_directory):
|
def remove_open_source_project_only_files():
|
||||||
"""Generates and saves random secret key"""
|
file_names = [
|
||||||
# Determine the local_setting_file_location
|
'CONTRIBUTORS.txt',
|
||||||
local_setting = os.path.join(
|
]
|
||||||
project_directory,
|
for file_name in file_names:
|
||||||
'config/settings/local.py'
|
os.remove(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
)
|
|
||||||
|
|
||||||
# local.py settings file
|
|
||||||
set_secret_key(local_setting)
|
|
||||||
|
|
||||||
env_file = os.path.join(
|
|
||||||
project_directory,
|
|
||||||
'env.example'
|
|
||||||
)
|
|
||||||
|
|
||||||
# env.example file
|
|
||||||
set_secret_key(env_file)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_file(file_name):
|
def remove_gplv3_files():
|
||||||
if os.path.exists(file_name):
|
file_names = [
|
||||||
os.remove(file_name)
|
'COPYING',
|
||||||
|
]
|
||||||
|
for file_name in file_names:
|
||||||
|
os.remove(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
|
|
||||||
|
|
||||||
def remove_task_app(project_directory):
|
def remove_pycharm_files():
|
||||||
"""Removes the taskapp if celery isn't going to be used"""
|
idea_dir_path = os.path.join(PROJECT_DIR_PATH, '.idea')
|
||||||
# Determine the local_setting_file_location
|
if os.path.exists(idea_dir_path):
|
||||||
task_app_location = os.path.join(
|
shutil.rmtree(idea_dir_path)
|
||||||
PROJECT_DIRECTORY,
|
|
||||||
'{{ cookiecutter.project_slug }}/taskapp'
|
|
||||||
)
|
|
||||||
shutil.rmtree(task_app_location)
|
|
||||||
|
|
||||||
|
docs_dir_path = os.path.join(PROJECT_DIR_PATH, 'docs', 'pycharm')
|
||||||
def remove_pycharm_dir(project_directory):
|
if os.path.exists(docs_dir_path):
|
||||||
"""
|
shutil.rmtree(docs_dir_path)
|
||||||
Removes directories related to PyCharm
|
|
||||||
if it isn't going to be used
|
|
||||||
"""
|
|
||||||
idea_dir_location = os.path.join(PROJECT_DIRECTORY, '.idea/')
|
|
||||||
if os.path.exists(idea_dir_location):
|
|
||||||
shutil.rmtree(idea_dir_location)
|
|
||||||
|
|
||||||
docs_dir_location = os.path.join(PROJECT_DIRECTORY, 'docs/pycharm/')
|
|
||||||
if os.path.exists(docs_dir_location):
|
|
||||||
shutil.rmtree(docs_dir_location)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_heroku_files():
|
|
||||||
"""
|
|
||||||
Removes files needed for heroku if it isn't going to be used
|
|
||||||
"""
|
|
||||||
filenames = ["Procfile", "runtime.txt"]
|
|
||||||
for filename in ["Procfile", "runtime.txt"]:
|
|
||||||
file_name = os.path.join(PROJECT_DIRECTORY, filename)
|
|
||||||
remove_file(file_name)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_docker_files():
|
def remove_docker_files():
|
||||||
"""
|
shutil.rmtree(os.path.join(PROJECT_DIR_PATH, 'compose'))
|
||||||
Removes files needed for docker if it isn't going to be used
|
|
||||||
"""
|
|
||||||
for filename in ["local.yml", "production.yml", ".dockerignore"]:
|
|
||||||
filename = os.path.join(PROJECT_DIRECTORY, filename)
|
|
||||||
if os.path.exists(filename):
|
|
||||||
os.remove(filename)
|
|
||||||
|
|
||||||
shutil.rmtree(os.path.join(
|
file_names = [
|
||||||
PROJECT_DIRECTORY, "compose"
|
'local.yml',
|
||||||
))
|
'production.yml',
|
||||||
|
'.dockerignore',
|
||||||
|
]
|
||||||
|
for file_name in file_names:
|
||||||
|
os.remove(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_heroku_files():
|
||||||
|
file_names = [
|
||||||
|
'Procfile',
|
||||||
|
'runtime.txt',
|
||||||
|
]
|
||||||
|
for file_name in file_names:
|
||||||
|
remove_file(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_paas_files():
|
||||||
|
none_paas_files_left = True
|
||||||
|
|
||||||
|
if '{{ cookiecutter.use_heroku }}'.lower() == 'n':
|
||||||
|
remove_heroku_files()
|
||||||
|
none_paas_files_left &= True
|
||||||
|
else:
|
||||||
|
none_paas_files_left &= False
|
||||||
|
|
||||||
|
if none_paas_files_left:
|
||||||
|
remove_file(os.path.join(PROJECT_DIR_PATH, 'requirements.txt'))
|
||||||
|
|
||||||
|
|
||||||
def remove_grunt_files():
|
def remove_grunt_files():
|
||||||
"""
|
file_names = [
|
||||||
Removes files needed for grunt if it isn't going to be used
|
'Gruntfile.js',
|
||||||
"""
|
]
|
||||||
for filename in ["Gruntfile.js"]:
|
for file_name in file_names:
|
||||||
os.remove(os.path.join(
|
os.remove(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
PROJECT_DIRECTORY, filename
|
|
||||||
))
|
|
||||||
|
|
||||||
def remove_gulp_files():
|
def remove_gulp_files():
|
||||||
|
file_names = [
|
||||||
|
'gulpfile.js',
|
||||||
|
]
|
||||||
|
for file_name in file_names:
|
||||||
|
os.remove(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_packagejson_file():
|
||||||
|
file_names = [
|
||||||
|
'package.json',
|
||||||
|
]
|
||||||
|
for file_name in file_names:
|
||||||
|
os.remove(os.path.join(PROJECT_DIR_PATH, file_name))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_celery_app():
|
||||||
|
shutil.rmtree(os.path.join(PROJECT_DIR_PATH, '{{ cookiecutter.project_slug }}', 'taskapp'))
|
||||||
|
|
||||||
|
|
||||||
|
def append_to_project_gitignore(path):
|
||||||
|
gitignore_file_path = os.path.join(PROJECT_DIR_PATH, '.gitignore')
|
||||||
|
with open(gitignore_file_path, 'a') as gitignore_file:
|
||||||
|
gitignore_file.write(path)
|
||||||
|
gitignore_file.write(os.linesep)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_string(length,
|
||||||
|
using_digits=False,
|
||||||
|
using_ascii_letters=False,
|
||||||
|
using_punctuation=False):
|
||||||
"""
|
"""
|
||||||
Removes files needed for grunt if it isn't going to be used
|
Example:
|
||||||
|
opting out for 50 symbol-long, [a-z][A-Z][0-9] string
|
||||||
|
would yield log_2((26+26+50)^50) ~= 334 bit strength.
|
||||||
"""
|
"""
|
||||||
for filename in ["gulpfile.js"]:
|
if not using_sysrandom:
|
||||||
os.remove(os.path.join(
|
return None
|
||||||
PROJECT_DIRECTORY, filename
|
|
||||||
))
|
|
||||||
|
|
||||||
def remove_packageJSON_file():
|
symbols = []
|
||||||
"""
|
if using_digits:
|
||||||
Removes files needed for grunt if it isn't going to be used
|
symbols += string.digits
|
||||||
"""
|
if using_ascii_letters:
|
||||||
for filename in ["package.json"]:
|
symbols += string.ascii_letters
|
||||||
os.remove(os.path.join(
|
if using_punctuation:
|
||||||
PROJECT_DIRECTORY, filename
|
symbols += string.punctuation \
|
||||||
))
|
.replace('"', '') \
|
||||||
|
.replace("'", '') \
|
||||||
def remove_copying_files():
|
.replace('\\', '')
|
||||||
"""
|
return ''.join([random.choice(symbols) for _ in range(length)])
|
||||||
Removes files needed for the GPLv3 licence if it isn't going to be used
|
|
||||||
"""
|
|
||||||
for filename in ["COPYING"]:
|
|
||||||
os.remove(os.path.join(
|
|
||||||
PROJECT_DIRECTORY, filename
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
# IN PROGRESS
|
def set_flag(file_path,
|
||||||
# def copy_doc_files(project_directory):
|
flag,
|
||||||
# cookiecutters_dir = DEFAULT_CONFIG['cookiecutters_dir']
|
value=None,
|
||||||
# cookiecutter_django_dir = os.path.join(
|
*args,
|
||||||
# cookiecutters_dir,
|
**kwargs):
|
||||||
# 'cookiecutter-django',
|
if value is None:
|
||||||
# 'docs'
|
random_string = generate_random_string(*args, **kwargs)
|
||||||
# )
|
if random_string is None:
|
||||||
# target_dir = os.path.join(
|
import sys
|
||||||
# project_directory,
|
sys.stdout.write(
|
||||||
# 'docs'
|
"We couldn't find a secure pseudo-random number generator on your system. "
|
||||||
# )
|
"Please, make sure to manually {} later.".format(flag)
|
||||||
# for name in os.listdir(cookiecutter_django_dir):
|
)
|
||||||
# if name.endswith('.rst') and not name.startswith('index'):
|
random_string = flag
|
||||||
# src = os.path.join(cookiecutter_django_dir, name)
|
value = random_string
|
||||||
# dst = os.path.join(target_dir, name)
|
|
||||||
# shutil.copyfile(src, dst)
|
|
||||||
|
|
||||||
# 1. Generates and saves random secret key
|
with open(file_path, 'r+') as f:
|
||||||
make_secret_key(PROJECT_DIRECTORY)
|
file_contents = f.read().replace(flag, value)
|
||||||
|
f.seek(0)
|
||||||
|
f.write(file_contents)
|
||||||
|
f.truncate()
|
||||||
|
|
||||||
# 2. Removes the taskapp if celery isn't going to be used
|
return value
|
||||||
if '{{ cookiecutter.use_celery }}'.lower() == 'n':
|
|
||||||
remove_task_app(PROJECT_DIRECTORY)
|
|
||||||
|
|
||||||
# 3. Removes the .idea directory if PyCharm isn't going to be used
|
|
||||||
if '{{ cookiecutter.use_pycharm }}'.lower() != 'y':
|
|
||||||
remove_pycharm_dir(PROJECT_DIRECTORY)
|
|
||||||
|
|
||||||
# 4. Removes all heroku files if it isn't going to be used
|
def set_django_secret_key(file_path):
|
||||||
if '{{ cookiecutter.use_heroku }}'.lower() != 'y':
|
django_secret_key = set_flag(
|
||||||
remove_heroku_files()
|
file_path,
|
||||||
|
'!!!SET DJANGO_SECRET_KEY!!!',
|
||||||
|
length=50,
|
||||||
|
using_digits=True,
|
||||||
|
using_ascii_letters=True
|
||||||
|
)
|
||||||
|
return django_secret_key
|
||||||
|
|
||||||
# 5. Removes all docker files if it isn't going to be used
|
|
||||||
if '{{ cookiecutter.use_docker }}'.lower() != 'y':
|
def set_postgres_user(file_path,
|
||||||
|
value=None):
|
||||||
|
postgres_user = set_flag(
|
||||||
|
file_path,
|
||||||
|
'!!!SET POSTGRES_USER!!!',
|
||||||
|
value=value,
|
||||||
|
length=8,
|
||||||
|
using_ascii_letters=True
|
||||||
|
)
|
||||||
|
return postgres_user
|
||||||
|
|
||||||
|
|
||||||
|
def set_postgres_password(file_path):
|
||||||
|
postgres_password = set_flag(
|
||||||
|
file_path,
|
||||||
|
'!!!SET POSTGRES_PASSWORD!!!',
|
||||||
|
length=42,
|
||||||
|
using_digits=True,
|
||||||
|
using_ascii_letters=True
|
||||||
|
)
|
||||||
|
return postgres_password
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_dotenv(postgres_user):
|
||||||
|
# Initializing `env.example` first.
|
||||||
|
envexample_file_path = os.path.join(PROJECT_DIR_PATH, 'env.example')
|
||||||
|
set_django_secret_key(envexample_file_path)
|
||||||
|
set_postgres_user(envexample_file_path, value=postgres_user)
|
||||||
|
set_postgres_password(envexample_file_path)
|
||||||
|
# Renaming `env.example` to `.env`.
|
||||||
|
dotenv_file_path = os.path.join(PROJECT_DIR_PATH, '.env')
|
||||||
|
shutil.move(envexample_file_path, dotenv_file_path)
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_localyml(postgres_user):
|
||||||
|
set_postgres_user(os.path.join(PROJECT_DIR_PATH, 'local.yml'), value=postgres_user)
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_local_settings():
|
||||||
|
set_django_secret_key(os.path.join(PROJECT_DIR_PATH, 'config', 'settings', 'local.py'))
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_test_settings():
|
||||||
|
set_django_secret_key(os.path.join(PROJECT_DIR_PATH, 'config', 'settings', 'test.py'))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
postgres_user = generate_random_string(length=16, using_ascii_letters=True)
|
||||||
|
initialize_dotenv(postgres_user)
|
||||||
|
initialize_localyml(postgres_user)
|
||||||
|
initialize_local_settings()
|
||||||
|
initialize_test_settings()
|
||||||
|
|
||||||
|
if '{{ cookiecutter.open_source_license }}' == 'Not open source':
|
||||||
|
remove_open_source_project_only_files()
|
||||||
|
elif '{{ cookiecutter.open_source_license}}' != 'GPLv3':
|
||||||
|
remove_gplv3_files()
|
||||||
|
|
||||||
|
if '{{ cookiecutter.use_pycharm }}'.lower() == 'n':
|
||||||
|
remove_pycharm_files()
|
||||||
|
|
||||||
|
if '{{ cookiecutter.use_docker }}'.lower() == 'n':
|
||||||
remove_docker_files()
|
remove_docker_files()
|
||||||
|
|
||||||
# 6. Removes all JS task manager files if it isn't going to be used
|
remove_paas_files()
|
||||||
|
|
||||||
if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp':
|
if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp':
|
||||||
remove_grunt_files()
|
remove_grunt_files()
|
||||||
elif '{{ cookiecutter.js_task_runner}}'.lower() == 'grunt':
|
elif '{{ cookiecutter.js_task_runner}}'.lower() == 'grunt':
|
||||||
|
@ -221,18 +259,25 @@ elif '{{ cookiecutter.js_task_runner}}'.lower() == 'grunt':
|
||||||
else:
|
else:
|
||||||
remove_gulp_files()
|
remove_gulp_files()
|
||||||
remove_grunt_files()
|
remove_grunt_files()
|
||||||
remove_packageJSON_file()
|
remove_packagejson_file()
|
||||||
|
|
||||||
|
if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] \
|
||||||
# 9. Display a warning if use_docker and use_grunt are selected. Grunt isn't
|
and '{{ cookiecutter.use_docker }}'.lower() == 'y':
|
||||||
# supported by our docker config atm.
|
TERMINATOR = "\x1b[0m"
|
||||||
if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] and '{{ cookiecutter.use_docker }}'.lower() == 'y':
|
INFO = "\x1b[1;33m [INFO]: "
|
||||||
print(
|
sys.stdout.write(
|
||||||
"You selected to use docker and a JS task runner. This is NOT supported out of the box for now. You "
|
INFO +
|
||||||
"can continue to use the project like you normally would, but you will need to add a "
|
"Docker and {} JS task runner ".format('{{ cookiecutter.js_task_runner }}'.lower().capitalize()) +
|
||||||
"js task runner service to your docker configuration manually."
|
"working together not supported yet. "
|
||||||
|
"You can continue using the generated project like you normally would, "
|
||||||
|
"however you would need to add a JS task runner service "
|
||||||
|
"to your Docker Compose configuration manually." +
|
||||||
|
TERMINATOR
|
||||||
)
|
)
|
||||||
|
|
||||||
# 10. Removes files needed for the GPLv3 licence if it isn't going to be used.
|
if '{{ cookiecutter.use_celery }}'.lower() == 'n':
|
||||||
if '{{ cookiecutter.open_source_license}}' != 'GPLv3':
|
remove_celery_app()
|
||||||
remove_copying_files()
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
|
@ -1,27 +1,62 @@
|
||||||
|
"""
|
||||||
|
NOTE:
|
||||||
|
the below code is to be maintained Python 2.x-compatible
|
||||||
|
as the whole Cookiecutter Django project initialization
|
||||||
|
can potentially be run in Python 2.x environment.
|
||||||
|
|
||||||
|
TODO: ? restrict Cookiecutter Django project initialization to Python 3.x environments only
|
||||||
|
"""
|
||||||
|
|
||||||
project_slug = '{{ cookiecutter.project_slug }}'
|
project_slug = '{{ cookiecutter.project_slug }}'
|
||||||
|
|
||||||
if hasattr(project_slug, 'isidentifier'):
|
if hasattr(project_slug, 'isidentifier'):
|
||||||
assert project_slug.isidentifier(), 'Project slug should be valid Python identifier!'
|
assert project_slug.isidentifier(), "'{}' project slug is not a valid Python identifier.".format(project_slug)
|
||||||
|
|
||||||
heroku = '{{ cookiecutter.use_heroku }}'.lower()
|
assert "\\" not in "{{ cookiecutter.author_name }}", "Don't include backslashes in author name."
|
||||||
docker = '{{ cookiecutter.use_docker }}'.lower()
|
|
||||||
|
|
||||||
|
using_docker = '{{ cookiecutter.use_docker }}'.lower()
|
||||||
|
if using_docker == 'n':
|
||||||
|
TERMINATOR = "\x1b[0m"
|
||||||
|
WARNING = "\x1b[1;33m [WARNING]: "
|
||||||
|
INFO = "\x1b[1;33m [INFO]: "
|
||||||
|
HINT = "\x1b[3;33m"
|
||||||
|
SUCCESS = "\x1b[1;32m [SUCCESS]: "
|
||||||
|
|
||||||
if docker == 'n':
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
python_major_version = sys.version_info[0]
|
python_major_version = sys.version_info[0]
|
||||||
|
|
||||||
if python_major_version == 2:
|
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)")
|
sys.stdout.write(
|
||||||
|
WARNING +
|
||||||
yes_options = set(['y'])
|
"Cookiecutter Django does not support Python 2. "
|
||||||
no_options = set(['n', ''])
|
"Stability is guaranteed with Python 3.6+ only, "
|
||||||
|
"are you sure you want to proceed (y/n)? " +
|
||||||
|
TERMINATOR
|
||||||
|
)
|
||||||
|
yes_options, no_options = frozenset(['y']), frozenset(['n'])
|
||||||
|
while True:
|
||||||
choice = raw_input().lower()
|
choice = raw_input().lower()
|
||||||
if choice in no_options:
|
if choice in yes_options:
|
||||||
|
break
|
||||||
|
elif choice in no_options:
|
||||||
|
sys.stdout.write(
|
||||||
|
INFO +
|
||||||
|
"Generation process stopped as requested." +
|
||||||
|
TERMINATOR
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif choice in yes_options:
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
sys.stdout.write("Please respond with %s or %s"
|
sys.stdout.write(
|
||||||
% (', '.join([o for o in yes_options if not o == ''])
|
HINT +
|
||||||
, ', '.join([o for o in no_options if not o == ''])))
|
"Please respond with {} or {}: ".format(
|
||||||
|
', '.join(["'{}'".format(o) for o in yes_options if not o == '']),
|
||||||
|
', '.join(["'{}'".format(o) for o in no_options if not o == ''])
|
||||||
|
) +
|
||||||
|
TERMINATOR
|
||||||
|
)
|
||||||
|
|
||||||
|
sys.stdout.write(
|
||||||
|
SUCCESS +
|
||||||
|
"Project initialized, keep up the good work!" +
|
||||||
|
TERMINATOR
|
||||||
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@ sh==1.12.14
|
||||||
binaryornot==0.4.4
|
binaryornot==0.4.4
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
pytest==3.3.2
|
pytest==3.4.1
|
||||||
pycodestyle==2.3.1
|
pycodestyle==2.3.1
|
||||||
pyflakes==1.6.0
|
pyflakes==1.6.0
|
||||||
tox==2.9.1
|
tox==2.9.1
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
# These requirements prevented an upgrade to Django 1.10.
|
# These requirements prevented an upgrade to Django 1.11.
|
||||||
django-coverage-plugin==1.5.0
|
|
||||||
django-autoslug==1.9.3
|
django-autoslug==1.9.3
|
||||||
|
|
||||||
|
|
8
setup.py
8
setup.py
|
@ -10,7 +10,7 @@ except ImportError:
|
||||||
|
|
||||||
# Our version ALWAYS matches the version of Django we support
|
# 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.
|
# If Django has a new release, we branch, tag, then update this setting after the tag.
|
||||||
version = '1.11.9'
|
version = '2.0.2'
|
||||||
|
|
||||||
if sys.argv[-1] == 'tag':
|
if sys.argv[-1] == 'tag':
|
||||||
os.system('git tag -a %s -m "version %s"' % (version, version))
|
os.system('git tag -a %s -m "version %s"' % (version, version))
|
||||||
|
@ -34,16 +34,14 @@ setup(
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
'Environment :: Console',
|
'Environment :: Console',
|
||||||
'Framework :: Django :: 1.10',
|
'Framework :: Django :: 2.0',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'Natural Language :: English',
|
'Natural Language :: English',
|
||||||
'License :: OSI Approved :: BSD License',
|
'License :: OSI Approved :: BSD License',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3.5',
|
|
||||||
'Programming Language :: Python :: Implementation :: CPython',
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
'Programming Language :: Python :: Implementation :: PyPy',
|
|
||||||
'Topic :: Software Development',
|
'Topic :: Software Development',
|
||||||
],
|
],
|
||||||
keywords=(
|
keywords=(
|
||||||
|
|
|
@ -19,3 +19,6 @@ docker-compose -f local.yml run django python manage.py test
|
||||||
|
|
||||||
# return non-zero status code if there are migrations that have not been created
|
# return non-zero status code if there are migrations that have not been created
|
||||||
docker-compose -f local.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; }
|
docker-compose -f local.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; }
|
||||||
|
|
||||||
|
# Test support for translations
|
||||||
|
docker-compose -f local.yml run --rm django python manage.py makemessages
|
||||||
|
|
|
@ -8,4 +8,4 @@ before_install:
|
||||||
- sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm
|
- sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "3.5"
|
- "3.6"
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
FROM python:3.5
|
FROM python:3.6-alpine
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
|
RUN apk update \
|
||||||
|
# psycopg2 dependencies
|
||||||
|
&& apk add --virtual build-deps gcc python3-dev musl-dev \
|
||||||
|
&& apk add postgresql-dev \
|
||||||
|
# Pillow dependencies
|
||||||
|
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
||||||
|
# CFFI dependencies
|
||||||
|
&& apk add libffi-dev openssl-dev py-cffi \
|
||||||
|
# Translations dependencies
|
||||||
|
&& apk add gettext
|
||||||
|
|
||||||
# Requirements have to be pulled and installed here, otherwise caching won't work
|
# Requirements have to be pulled and installed here, otherwise caching won't work
|
||||||
COPY ./requirements /requirements
|
COPY ./requirements /requirements
|
||||||
RUN pip install -r /requirements/local.txt
|
RUN pip install -r /requirements/local.txt
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
FROM python:3.5
|
FROM python:3.6-alpine
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
RUN groupadd -r django \
|
RUN apk update \
|
||||||
&& useradd -r -g django django
|
# psycopg2 dependencies
|
||||||
|
&& apk add --virtual build-deps gcc python3-dev musl-dev \
|
||||||
|
&& apk add postgresql-dev \
|
||||||
|
# Pillow dependencies
|
||||||
|
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
||||||
|
# CFFI dependencies
|
||||||
|
&& apk add libffi-dev openssl-dev py-cffi
|
||||||
|
|
||||||
|
RUN addgroup -S django \
|
||||||
|
&& adduser -S -G django django
|
||||||
|
|
||||||
# Requirements have to be pulled and installed here, otherwise caching won't work
|
# Requirements have to be pulled and installed here, otherwise caching won't work
|
||||||
COPY ./requirements /requirements
|
COPY ./requirements /requirements
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
@ -25,7 +25,7 @@ export DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$
|
||||||
export CELERY_BROKER_URL=$REDIS_URL/0
|
export CELERY_BROKER_URL=$REDIS_URL/0
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
function postgres_ready(){
|
postgres_ready() {
|
||||||
python << END
|
python << END
|
||||||
import sys
|
import sys
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -24,7 +24,7 @@ TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
# Note: This key only used for development and testing.
|
# Note: This key only used for development and testing.
|
||||||
SECRET_KEY = env('DJANGO_SECRET_KEY', default='CHANGEME!!!')
|
SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!')
|
||||||
|
|
||||||
# Mail settings
|
# Mail settings
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -103,12 +103,8 @@ AWS_QUERYSTRING_AUTH = False
|
||||||
# AWS cache settings, don't change unless you know what you're doing:
|
# AWS cache settings, don't change unless you know what you're doing:
|
||||||
AWS_EXPIRY = 60 * 60 * 24 * 7
|
AWS_EXPIRY = 60 * 60 * 24 * 7
|
||||||
|
|
||||||
# TODO See: https://github.com/jschneier/django-storages/issues/47
|
AWS_S3_OBJECT_PARAMETERS = {
|
||||||
# Revert the following and use str after the above-mentioned bug is fixed in
|
'CacheControl': 'max-age=%d, s-maxage=%d, must-revalidate' % (AWS_EXPIRY, AWS_EXPIRY),
|
||||||
# either django-storage-redux or boto
|
|
||||||
control = 'max-age=%d, s-maxage=%d, must-revalidate' % (AWS_EXPIRY, AWS_EXPIRY)
|
|
||||||
AWS_HEADERS = {
|
|
||||||
'Cache-Control': bytes(control, encoding='latin-1')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT, used for managing
|
# URL that handles the media served from MEDIA_ROOT, used for managing
|
||||||
|
@ -177,7 +173,7 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [
|
||||||
# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
|
# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
|
||||||
DATABASES['default'] = env.db('DATABASE_URL')
|
DATABASES['default'] = env.db('DATABASE_URL')
|
||||||
DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default={{ _DEFAULT_CONN_MAX_AGE }})
|
DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default={{ _DEFAULT_CONN_MAX_AGE }})
|
||||||
|
DATABASES['default']['ATOMIC_REQUESTS'] = True
|
||||||
|
|
||||||
# CACHING
|
# CACHING
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -17,7 +17,7 @@ TEMPLATES[0]['OPTIONS']['debug'] = False
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
# Note: This key only used for development and testing.
|
# Note: This key only used for development and testing.
|
||||||
SECRET_KEY = env('DJANGO_SECRET_KEY', default='CHANGEME!!!')
|
SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!')
|
||||||
|
|
||||||
# Mail settings
|
# Mail settings
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -58,7 +58,7 @@ The `Docker compose documentation`_ explains in detail what you can accomplish i
|
||||||
build: database
|
build: database
|
||||||
webapp:
|
webapp:
|
||||||
build: webapp:
|
build: webapp:
|
||||||
command: /usr/bin/python3.4 manage.py runserver 0.0.0.0:8000 # dev setting
|
command: /usr/bin/python3.6 manage.py runserver 0.0.0.0:8000 # dev setting
|
||||||
# command: gunicorn -b 0.0.0.0:8000 wsgi:application # production setting
|
# command: gunicorn -b 0.0.0.0:8000 wsgi:application # production setting
|
||||||
volumes:
|
volumes:
|
||||||
- webapp/your_project_name:/path/to/container/workdir/
|
- webapp/your_project_name:/path/to/container/workdir/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
# PostgreSQL
|
# PostgreSQL
|
||||||
POSTGRES_PASSWORD=mysecretpass
|
POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!!
|
||||||
POSTGRES_USER=postgresuser
|
POSTGRES_USER=!!!SET POSTGRES_USER!!!
|
||||||
CONN_MAX_AGE=
|
CONN_MAX_AGE=
|
||||||
|
|
||||||
# Domain name, used by caddy
|
# Domain name, used by caddy
|
||||||
|
@ -11,7 +11,7 @@ DOMAIN_NAME={{ cookiecutter.domain_name }}
|
||||||
# DJANGO_READ_DOT_ENV_FILE=True
|
# DJANGO_READ_DOT_ENV_FILE=True
|
||||||
DJANGO_ADMIN_URL=
|
DJANGO_ADMIN_URL=
|
||||||
DJANGO_SETTINGS_MODULE=config.settings.production
|
DJANGO_SETTINGS_MODULE=config.settings.production
|
||||||
DJANGO_SECRET_KEY=CHANGEME!!!
|
DJANGO_SECRET_KEY=!!!SET DJANGO_SECRET_KEY!!!
|
||||||
DJANGO_ALLOWED_HOSTS=.{{ cookiecutter.domain_name }}
|
DJANGO_ALLOWED_HOSTS=.{{ cookiecutter.domain_name }}
|
||||||
|
|
||||||
# AWS Settings
|
# AWS Settings
|
||||||
|
|
|
@ -15,7 +15,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app
|
- .:/app
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER={{cookiecutter.project_slug}}
|
- POSTGRES_USER=!!!SET POSTGRES_USER!!!
|
||||||
- USE_DOCKER=yes
|
- USE_DOCKER=yes
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
|
@ -29,7 +29,7 @@ services:
|
||||||
- postgres_data_local:/var/lib/postgresql/data
|
- postgres_data_local:/var/lib/postgresql/data
|
||||||
- postgres_backup_local:/backups
|
- postgres_backup_local:/backups
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER={{cookiecutter.project_slug}}
|
- POSTGRES_USER=!!!SET POSTGRES_USER!!!
|
||||||
{% if cookiecutter.use_mailhog == 'y' %}
|
{% if cookiecutter.use_mailhog == 'y' %}
|
||||||
mailhog:
|
mailhog:
|
||||||
image: mailhog/mailhog:v1.0.0
|
image: mailhog/mailhog:v1.0.0
|
||||||
|
|
6
{{cookiecutter.project_slug}}/locale/README.rst
Normal file
6
{{cookiecutter.project_slug}}/locale/README.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Translations
|
||||||
|
============
|
||||||
|
|
||||||
|
Translations will be placed in this folder when running::
|
||||||
|
|
||||||
|
python manage.py makemessages
|
|
@ -6,7 +6,7 @@ wheel==0.30.0
|
||||||
|
|
||||||
|
|
||||||
# Conservative Django
|
# Conservative Django
|
||||||
django==1.11.10 # pyup: <2.0
|
django==2.0.2 # pyup: < 2.1
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
django-environ==0.4.4
|
django-environ==0.4.4
|
||||||
|
@ -36,21 +36,21 @@ django-allauth==0.35.0
|
||||||
# from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg
|
# from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg
|
||||||
{% else %}
|
{% else %}
|
||||||
# Python-PostgreSQL Database Adapter
|
# Python-PostgreSQL Database Adapter
|
||||||
psycopg2==2.7.3.2
|
psycopg2==2.7.4 --no-binary psycopg2
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Unicode slugification
|
# Unicode slugification
|
||||||
awesome-slugify==1.6.5
|
awesome-slugify==1.6.5
|
||||||
|
|
||||||
# Time zones support
|
# Time zones support
|
||||||
pytz==2017.3
|
pytz==2018.3
|
||||||
|
|
||||||
# Redis support
|
# Redis support
|
||||||
django-redis==4.8.0
|
django-redis==4.8.0
|
||||||
redis>=2.10.5
|
redis>=2.10.5
|
||||||
|
|
||||||
{% if cookiecutter.use_celery == "y" %}
|
{% if cookiecutter.use_celery == "y" %}
|
||||||
celery==3.1.25
|
celery==3.1.25 # pyup: <4.0
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if cookiecutter.use_compressor == "y" %}
|
{% if cookiecutter.use_compressor == "y" %}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# Local development dependencies go here
|
# Local development dependencies go here
|
||||||
-r base.txt
|
-r base.txt
|
||||||
|
|
||||||
coverage==4.5
|
coverage==4.5.1
|
||||||
django-coverage-plugin==1.5.0
|
django-coverage-plugin==1.5.0
|
||||||
|
|
||||||
Sphinx==1.6.7
|
Sphinx==1.7.1
|
||||||
django-extensions==1.9.9
|
django-extensions==2.0.0
|
||||||
Werkzeug==0.14.1
|
Werkzeug==0.14.1
|
||||||
django-test-plus==1.0.22
|
django-test-plus==1.0.22
|
||||||
factory-boy==2.10.0
|
factory-boy==2.10.0
|
||||||
|
@ -13,7 +13,7 @@ factory-boy==2.10.0
|
||||||
django-debug-toolbar==1.9.1
|
django-debug-toolbar==1.9.1
|
||||||
|
|
||||||
# improved REPL
|
# improved REPL
|
||||||
ipdb==0.10.3
|
ipdb==0.11
|
||||||
|
|
||||||
pytest-django==3.1.2
|
pytest-django==3.1.2
|
||||||
pytest-sugar==0.9.0
|
pytest-sugar==0.9.1
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# Python-PostgreSQL Database Adapter
|
# Python-PostgreSQL Database Adapter
|
||||||
# Assuming Windows is used locally, and *nix -- in production.
|
# Assuming Windows is used locally, and *nix -- in production.
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
psycopg2==2.7.3.2
|
psycopg2==2.7.4 --no-binary psycopg2
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# WSGI Handler
|
# WSGI Handler
|
||||||
|
@ -16,7 +16,7 @@ gunicorn==19.7.1
|
||||||
|
|
||||||
# Static and Media Storage
|
# Static and Media Storage
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
boto3==1.5.22
|
boto3==1.5.36
|
||||||
django-storages==1.6.5
|
django-storages==1.6.5
|
||||||
{% if cookiecutter.use_whitenoise != 'y' -%}
|
{% if cookiecutter.use_whitenoise != 'y' -%}
|
||||||
Collectfast==0.6.0
|
Collectfast==0.6.0
|
||||||
|
@ -24,7 +24,7 @@ Collectfast==0.6.0
|
||||||
|
|
||||||
# Email backends for Mailgun, Postmark, SendGrid and more
|
# Email backends for Mailgun, Postmark, SendGrid and more
|
||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
django-anymail==1.3
|
django-anymail==1.4
|
||||||
|
|
||||||
{% if cookiecutter.use_sentry_for_error_reporting == "y" -%}
|
{% if cookiecutter.use_sentry_for_error_reporting == "y" -%}
|
||||||
# Raven is the Sentry client
|
# Raven is the Sentry client
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
{% if cookiecutter.windows == 'y' -%}
|
{% if cookiecutter.windows == 'y' -%}
|
||||||
# Python-PostgreSQL Database Adapter
|
# Python-PostgreSQL Database Adapter
|
||||||
# If using Win for dev, this assumes Unix in test/prod
|
# If using Win for dev, this assumes Unix in test/prod
|
||||||
psycopg2==2.7.3.2
|
psycopg2==2.7.4
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
coverage==4.5
|
coverage==4.5.1
|
||||||
flake8==3.5.0 # pyup: != 2.6.0
|
flake8==3.5.0 # pyup: != 2.6.0
|
||||||
django-test-plus==1.0.22
|
django-test-plus==1.0.22
|
||||||
factory-boy==2.10.0
|
factory-boy==2.10.0
|
||||||
|
@ -15,4 +15,4 @@ django-coverage-plugin==1.5.0
|
||||||
|
|
||||||
# pytest
|
# pytest
|
||||||
pytest-django==3.1.2
|
pytest-django==3.1.2
|
||||||
pytest-sugar==0.9.0
|
pytest-sugar==0.9.1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
python-3.6.2
|
python-3.6.4
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
##basic build dependencies of various Django apps for Debian Jessie 9.x
|
||||||
|
#build-essential metapackage install: make, gcc, g++,
|
||||||
|
build-essential
|
||||||
|
#required to translate
|
||||||
|
gettext
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
##shared dependencies of:
|
||||||
|
##Pillow, pylibmc
|
||||||
|
zlib1g-dev
|
||||||
|
|
||||||
|
##Postgresql and psycopg2 dependencies
|
||||||
|
libpq-dev
|
||||||
|
|
||||||
|
##Pillow dependencies
|
||||||
|
libtiff5-dev
|
||||||
|
libjpeg62-turbo-dev
|
||||||
|
libfreetype6-dev
|
||||||
|
liblcms2-dev
|
||||||
|
libwebp-dev
|
||||||
|
|
||||||
|
##django-extensions
|
||||||
|
graphviz-dev
|
|
@ -22,7 +22,7 @@
|
||||||
<!-- Your stuff: Third-party CSS libraries go here -->
|
<!-- Your stuff: Third-party CSS libraries go here -->
|
||||||
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %}
|
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %}
|
||||||
<!-- This file stores project-specific CSS -->
|
<!-- This file stores project-specific CSS -->
|
||||||
{% endraw %}{% if cookiecutter.js_task_runner == "Gulp" %}{% raw %}
|
{% endraw %}{% if cookiecutter.js_task_runner == "Gulp" and cookiecutter.use_compressor == "n" %}{% raw %}
|
||||||
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
|
||||||
{% endraw %}{% else %}{% raw %}
|
{% endraw %}{% else %}{% raw %}
|
||||||
<link href="{% static 'css/project.css' %}" rel="stylesheet">
|
<link href="{% static 'css/project.css' %}" rel="stylesheet">
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Migration(migrations.Migration):
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||||
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
|
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
|
||||||
('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')),
|
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
|
|
||||||
# First Name and Last Name do not cover name patterns
|
# First Name and Last Name do not cover name patterns
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.core.urlresolvers import reverse, resolve
|
from django.urls import reverse, resolve
|
||||||
|
|
||||||
from test_plus.test import TestCase
|
from test_plus.test import TestCase
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.conf.urls import url
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'users'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(
|
url(
|
||||||
regex=r'^$',
|
regex=r'^$',
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
|
||||||
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
||||||
|
|
||||||
from .models import User
|
from .models import User
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user