Dica 1 - Django boilerplate e cookiecutter-django
Versões usadas no vídeo: Python 3.8.2; Django 2.2.13 (boilerplatesimple.sh), Django 2.2.12 com Bootstrap 3 (boilerplate2.sh) e Django 3.0 (cookiecutter-django de junho de 2020).
Importante: nas próximas dicas, troque
Ou seja, remova a \ no meio das tags. (Isso era necessário quando o site era feito com o GitBook; hoje as tags de template já aparecem normais, como {% block content %}.)
Começar um projeto Django do zero sempre passa pelas mesmas tarefas: criar a virtualenv, instalar o Django e as bibliotecas de sempre, rodar o startproject, criar um app, tirar a SECRET_KEY do settings.py, configurar o banco, as URLs, o superusuário... Um boilerplate é um esqueleto pronto que faz tudo isso de uma vez, para você já começar escrevendo o código da sua aplicação.
Nesta primeira dica vamos ver três opções, da mais simples para a mais completa:
- boilerplatesimple.sh: um shell script que cria um projeto Django mínimo, com
settings.pyconfigurado e um appcorevazio. - boilerplate2.sh: um shell script que cria um projeto completo, com um cadastro de contatos (CRUD), templates, testes, Selenium e dados de exemplo.
- cookiecutter-django: o boilerplate "profissional" criado pelo Daniel Roy Greenfeld (pydanny), com PostgreSQL, cadastro de usuários com confirmação de e-mail, debug toolbar e muito mais.
Depois deste vídeo, o boilerplate virou um repositório: django-boilerplate. Veja a Dica 1.1 - Django boilerplate.
Pré-requisitos
- Linux ou macOS com
bash,curl(ouwget) e Python 3 (no vídeo, Python 3.8.2, no Ubuntu). - Para os dois shell scripts: o
seddo GNU (o padrão do Linux). Os scripts usamsed -ino formato do GNU, que não funciona com oseddo macOS. - Para o cookiecutter-django: PostgreSQL instalado e rodando.
Opção 1: boilerplatesimple.sh
Baixando o script
Crie uma pasta temporária e baixe o script do gist. O comando de download está no próprio cabeçalho do script:
mkdir /tmp/dica01
cd /tmp/dica01
curl https://gist.githubusercontent.com/rg3915/b363f5c4a998f42901705b23ccf4b8e8/raw/b759d5a4c1dd471a1c1851c2a9e7cbc705f11ac1/boilerplatesimple.sh -o boilerplatesimple.sh
O link acima aponta para a revisão do gist usada no vídeo (V 0.1.1, de 06/06/2020). Se preferir o wget:
wget https://gist.githubusercontent.com/rg3915/b363f5c4a998f42901705b23ccf4b8e8/raw/b759d5a4c1dd471a1c1851c2a9e7cbc705f11ac1/boilerplatesimple.sh -O boilerplatesimple.sh
Antes de rodar, confira o script
Uma dica importante: nunca rode um script baixado da internet sem olhar o que ele faz. No mínimo, procure por rm, que apaga arquivos. No vídeo isso é feito no vim:
vim boilerplatesimple.sh
Dentro do vim, digite /rm e Enter. Neste script a busca termina com E486: Padrão não encontrado: rm, ou seja, não há nenhum rm nele.
O cabeçalho do script diz o que ele faz:
# V 0.1.1
# 2020-06-06
# Shell script to create a very simple Django project.
# This script require Python 3.x and pyenv
# Settings.py is config to Django 2.2.13
# The project contains:
# Settings config
# Admin config
Rodando o script
O script é executado com source (e não com bash), porque ele ativa a virtualenv e isso precisa valer para o seu terminal. O nome do projeto é opcional; o padrão é myproject:
source boilerplatesimple.sh
# ou: source boilerplatesimple.sh outronome
A saída começa assim:
>>> The name of the project is 'myproject'.
>>> Creating README.md
>>> Creating virtualenv
>>> .venv is created
>>> activate the .venv
>>> Installing the Django
O que o script faz, na ordem:
- Cria o
README.mddo projeto. - Cria e ativa a virtualenv
.venv(python -m venv .venv). - Instala
django==2.2.13,dj-database-url,django-widget-tweaks,python-decoupleedjango-extensions, e grava orequirements.txtcompip freeze. - Cria
contrib/env_gen.pye roda esse arquivo para gerar o.envcom umaSECRET_KEYaleatória. - Cria o
.gitignore. - Roda
django-admin.py startproject myproject .e cria o appcoredentro da pasta do projeto (myproject/core). - Edita o
settings.pycomsed, criacore/urls.pye reescreve ourls.pyprincipal. - Roda
makemigrationsemigratee pergunta se você quer criar um superusuário.
No fim, o migrate aplica as migrations do Django 2.2 e o script pergunta pelo superusuário:
Applying sessions.0001_initial... OK
Create superuser? (y/N) y
>>> Creating a 'admin' user ...
>>> The password must contain at least 8 characters.
>>> Password suggestions: demodemo
Responda y e digite a senha. O usuário é sempre admin. Use uma senha simples assim apenas em desenvolvimento.
O requirements.txt gerado no vídeo ficou assim:
dj-database-url==0.5.0
Django==2.2.13
django-extensions==2.2.9
django-widget-tweaks==1.4.8
python-decouple==3.3
pytz==2020.1
sqlparse==0.3.1
Os arquivos gerados
O contrib/env_gen.py gera o .env:
# contrib/env_gen.py
"""
Django SECRET_KEY generator.
"""
from django.utils.crypto import get_random_string
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
CONFIG_STRING = """
DEBUG=True
SECRET_KEY=%s
ALLOWED_HOSTS=127.0.0.1, .localhost
""".strip() % get_random_string(50, chars)
# Writing our configuration file to '.env'
with open('.env', 'w') as configfile:
configfile.write(CONFIG_STRING)
O .gitignore:
__pycache__/
*.py[cod]
*.sqlite3
*.env
*.DS_Store
.venv/
staticfiles/
.ipynb_checkpoints/
A estrutura final do projeto (vista com o comando tree, sem os __pycache__):
.
├── boilerplatesimple.sh
├── contrib
│ └── env_gen.py
├── db.sqlite3
├── manage.py
├── myproject
│ ├── core
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── README.md
└── requirements.txt
O models.py e o views.py do core vêm vazios, como o startapp cria:
# myproject/core/models.py
from django.db import models
# Create your models here.
O core/urls.py já vem com o esqueleto pronto. É só descomentar as linhas quando criar a primeira view:
# myproject/core/urls.py
from django.urls import path
# from myproject.core import views as v
app_name = 'core'
urlpatterns = [
# path('', v.index, name='index'),
]
O urls.py principal inclui as URLs do core com o namespace core:
# myproject/urls.py
from django.urls import include, path
from django.contrib import admin
urlpatterns = [
path('', include('myproject.core.urls', namespace='core')),
path('admin/', admin.site.urls),
]
E o settings.py lê SECRET_KEY, DEBUG e ALLOWED_HOSTS do .env com o python-decouple, usa o dj-database-url para o banco (SQLite por padrão, ou o que estiver em DATABASE_URL), registra o django_extensions e o app myproject.core, e define o STATIC_ROOT. Este é o arquivo completo gerado pelo script:
# myproject/settings.py
"""
Django settings for myproject project.
Generated by 'django-admin startproject' using Django 2.2.13.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
import os
from decouple import config, Csv
from dj_database_url import parse as dburl
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'myproject.core'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'myproject.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
default_dburl = 'sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3')
DATABASES = {
'default': config('DATABASE_URL', default=default_dburl, cast=dburl),
}
# Password validation
# https://docs.djangoproject.com/en/2.2/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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
Rodando o projeto
Como o script já rodou o migrate, basta subir o servidor:
python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
June 14, 2020 - 04:41:33
Django version 2.2.13, using settings 'myproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Em http://localhost:8000 aparece a página padrão do Django ("The install worked successfully! Congratulations!"), porque ainda não existe nenhuma view. O admin já funciona em /admin/, com o usuário admin. É um esqueleto mínimo, bom para testes rápidos ou para começar um projeto do seu jeito.
No fim, o script lembra: não suba o .env para um repositório público e apague o boilerplatesimple.sh.
Opção 2: boilerplate2.sh
O segundo script é bem mais completo: ele cria um projeto com um cadastro de contatos funcionando, com templates, testes, Selenium e dados de exemplo. Saia da virtualenv anterior e use outra pasta:
deactivate
cd ..
mkdir dica01-boilerplate
cd dica01-boilerplate
curl https://gist.githubusercontent.com/rg3915/a264d0ade860d2f2b4bf/raw/ac1cc2f36ba104b6b2cd38f050638f4c6f07fbe5/boilerplate2.sh -o boilerplate2.sh
O cabeçalho diz o que o projeto vai ter:
# Shell script to create a complete Django project.
# This script require Python 3.x and pyenv
# Settings.py is config to Django 2.2.12
# The project contains:
# Settings config
# Person model and form
# Person list and detail
# Person create, update and delete
# Admin config
# Tests
# Selenium test
# Manage shell
Antes de rodar, de novo, procure por rm no vim (/rm e depois n para ir à próxima ocorrência). Neste script aparecem dois, nenhum perigoso: rm -rf djangoproject, que apaga a pasta djangoproject (criada pelo próprio script) antes de recriá-la, e rm -f core/tests.py, que apaga o tests.py padrão do app, porque os testes vão para a pasta core/tests/.
source boilerplate2.sh
>>> The name of the project is 'myproject'.
>>> Remove djangoproject
>>> Creating djangoproject
>>> Creating README.md
>>> Creating virtualenv
>>> .venv is created
>>> activate the .venv
>>> Installing the Django
O script:
- Cria a pasta
djangoproject, entra nela, cria e ativa a.venv. - Instala
django==2.2.12,dj-database-url,django-daterange-filter,django-localflavor,django-widget-tweaks,python-decouple,pytz,seleniumedjango-extensions. - Cria o projeto
myprojecte o appcorecom models, forms, mixins, views, URLs, admin, templates (Bootstrap 3 e Font Awesome via CDN), CSS e testes. - Roda as migrations e os testes (
Ran 14 tests ... OK). - Popula o banco com
python manage.py shell_plus < shell/shell_person.py, que lê ofix/person.csve cria os contatos combulk_createe telefones aleatórios. - Faz um backup com
dumpdataemfixtures.json, pergunta pelo superusuário, roda os testes de novo e instalaipdbeipython[notebook]. - Mostra o
Makefilecom os atalhos do projeto.
O Makefile exibido no fim da instalação:
# Makefile
shell_person:
python manage.py shell_plus < shell/shell_person.py
selenium_person:
python selenium/selenium_person.py
createuser:
python manage.py createsuperuser --username='admin' --email=''
backup:
python manage.py dumpdata core --format=json --indent=2 > fixtures.json
load:
python manage.py loaddata fixtures.json
A estrutura gerada (resumida):
djangoproject
├── contrib
│ └── env-sample
├── db.sqlite3
├── fix
│ └── person.csv
├── fixtures.json
├── Makefile
├── manage.py
├── myproject
│ ├── core
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── forms.py
│ │ ├── migrations
│ │ ├── mixins.py
│ │ ├── models.py
│ │ ├── static
│ │ │ └── css
│ │ │ ├── main.css
│ │ │ └── social.css
│ │ ├── templates
│ │ │ ├── base.html
│ │ │ ├── core
│ │ │ │ ├── person_detail.html
│ │ │ │ ├── person_form.html
│ │ │ │ └── person_list.html
│ │ │ ├── footer.html
│ │ │ ├── index.html
│ │ │ ├── nav.html
│ │ │ └── pagination.html
│ │ ├── tests
│ │ │ ├── data.py
│ │ │ ├── test_form_person.py
│ │ │ ├── test_model_person.py
│ │ │ ├── test_view_person_detail.py
│ │ │ └── test_view_person_list.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── README.md
├── requirements.txt
├── selenium
│ └── selenium_person.py
└── shell
└── shell_person.py
Os models
O app tem dois models abstratos (TimeStampedModel e Address), o Person e o Phone:
# myproject/core/models.py
# ... (imports e PHONE_TYPE: veja o arquivo completo no gist)
class TimeStampedModel(models.Model):
created = models.DateTimeField(
# ...
class Meta:
abstract = True
# ... (Address: endereço, bairro, cidade, UF e CEP; também abstrato)
class Person(TimeStampedModel, Address):
first_name = models.CharField('nome', max_length=50)
last_name = models.CharField(
'sobrenome',
max_length=50,
null=True,
blank=True
)
email = models.EmailField(null=True, blank=True)
blocked = models.BooleanField('bloqueado', default=False)
class Meta:
ordering = ['first_name']
verbose_name = 'contato'
verbose_name_plural = 'contatos'
def __str__(self):
return ' '.join(filter(None, [self.first_name, self.last_name]))
full_name = property(__str__)
def get_absolute_url(self):
return r('core:person_detail', pk=self.pk)
# ... (Phone: veja o arquivo completo no gist)
Código completo: myproject/core/models.py, gerado pelo boilerplate2.sh
As views, o mixin de busca, o formulário e as URLs
As views são as genéricas do Django. A lista usa o NameSearchMixin, que filtra pelo campo de busca search_box (nome, sobrenome ou e-mail), e pagina de 10 em 10:
# myproject/core/mixins.py
from django.db.models import Q
class NameSearchMixin(object):
def get_queryset(self):
queryset = super(NameSearchMixin, self).get_queryset()
q = self.request.GET.get('search_box')
if q:
return queryset.filter(
Q(first_name__icontains=q) |
Q(last_name__icontains=q) |
Q(email__icontains=q))
return queryset
# myproject/core/views.py
from django.shortcuts import render
from django.urls import reverse_lazy as r
from django.views.generic import CreateView, ListView, DetailView
from django.views.generic import UpdateView, DeleteView
from .mixins import NameSearchMixin
from .models import Person
from .forms import PersonForm
def home(request):
return render(request, 'index.html')
class PersonList(NameSearchMixin, ListView):
model = Person
paginate_by = 10
person_detail = DetailView.as_view(model=Person)
person_create = CreateView.as_view(model=Person, form_class=PersonForm)
person_update = UpdateView.as_view(model=Person, form_class=PersonForm)
person_delete = DeleteView.as_view(model=Person, success_url=r('core:person_list'))
# myproject/core/forms.py
from django import forms
from .models import Person
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = (
'first_name',
'last_name',
'email',
'address',
'complement',
'district',
'city',
'uf',
'cep',
'blocked'
)
# myproject/core/urls.py
from django.urls import path
from myproject.core import views as c
app_name = 'core'
urlpatterns = [
path('', c.home, name='home'),
path('person/', c.PersonList.as_view(), name='person_list'),
path('person/add/', c.person_create, name='person_add'),
path('person/<int:pk>/', c.person_detail, name='person_detail'),
path('person/<int:pk>/edit/', c.person_update, name='person_edit'),
path('person/<int:pk>/delete/',
c.person_delete, name='person_delete'),
]
O admin já vem com os telefones em linha (TabularInline) e um filtro por intervalo de datas com o django-daterange-filter (assunto da Dica 5):
# myproject/core/admin.py
from daterange_filter.filter import DateRangeFilter
from django.contrib import admin
from .models import Person, Phone
from .forms import PersonForm
class PhoneInline(admin.TabularInline):
model = Phone
extra = 1
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
inlines = [PhoneInline]
list_display = ('__str__', 'email', 'phone', 'uf', 'created', 'blocked')
date_hierarchy = 'created'
search_fields = ('first_name', 'last_name', 'email')
list_filter = (
# 'uf',
('created', DateRangeFilter),
)
form = PersonForm
def phone(self, obj):
return obj.phone_set.first()
phone.short_description = 'telefone'
Os templates, o CSS, os testes e o script do Selenium são longos e estão completos no boilerplate2.sh.
Usando o projeto
python manage.py runserver
Em http://localhost:8000 já existe um layout com menu (Home, Lista de Contatos, Admin). No vídeo:
- Em Adicionar (
/person/add/) aparece o formulário "Novo Contato", com nome, sobrenome, e-mail, endereço, complemento, bairro, cidade, UF, CEP e bloqueado. Ao salvar, você vai para a página de detalhe do contato. - Na página de detalhe dá para editar (
/person/<pk>/edit/) e excluir (com uma página de confirmação). - A Lista de Contatos (
/person/) mostra nome, e-mail, telefone e UF, o total de contatos (32, vindos doperson.csv) e a paginação. O campo Localizar busca por nome, sobrenome ou e-mail, por exemplo/person/?search_box=elliot.
Opção 3: cookiecutter-django
O cookiecutter-django é um boilerplate criado pelo Daniel Roy Greenfeld (pydanny), com muitos contribuidores. Ele usa o Cookiecutter, uma ferramenta que gera projetos a partir de um modelo fazendo perguntas no terminal. A documentação explica cada opção.
Instalando o Cookiecutter
deactivate
cd ..
mkdir cookiecutter
cd cookiecutter
python -V
# Python 3.8.2
python -m venv .venv
source .venv/bin/activate
pip install "cookiecutter>=1.7.0"
Gerando o projeto
cookiecutter https://github.com/pydanny/cookiecutter-django
Se você já tinha baixado o modelo antes, ele pergunta se pode apagar e baixar de novo; responda que sim:
You've downloaded /home/regis/.cookiecutters/cookiecutter-django before. Is it okay to delete and re-download it? [yes]:
Depois vêm as perguntas. Entre colchetes está o valor padrão (Enter aceita o padrão). As respostas usadas no vídeo:
project_name [My Awesome Project]: myproject
project_slug [myproject]:
description [Behold My Awesome Project!]:
author_name [Daniel Roy Greenfeld]: Regis Santos
domain_name [example.com]:
email [regis-santos@example.com]:
version [0.1.0]:
Select open_source_license:
1 - MIT
2 - BSD
3 - GPLv3
4 - Apache Software License 2.0
5 - Not open source
Choose from 1, 2, 3, 4, 5 [1]:
timezone [UTC]:
windows [n]:
use_pycharm [n]:
use_docker [n]:
Select postgresql_version:
1 - 11.3
2 - 10.8
3 - 9.6
4 - 9.5
5 - 9.4
Choose from 1, 2, 3, 4, 5 [1]:
Select js_task_runner:
1 - None
2 - Gulp
Choose from 1, 2 [1]:
Select cloud_provider:
1 - AWS
2 - GCP
3 - None
Choose from 1, 2, 3 [1]:
Select mail_service:
1 - Mailgun
2 - Amazon SES
3 - Mailjet
4 - Mandrill
5 - Postmark
6 - Sendgrid
7 - SendinBlue
8 - SparkPost
9 - Other SMTP
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]:
use_async [n]:
use_drf [n]:
custom_bootstrap_compilation [n]:
use_compressor [n]:
use_celery [n]:
use_mailhog [n]:
use_sentry [n]:
use_whitenoise [n]:
use_heroku [n]: y
Select ci_tool:
1 - None
2 - Travis
3 - Gitlab
Choose from 1, 2, 3 [1]:
keep_local_envs_in_vcs [y]:
debug [n]:
Ou seja: projeto myproject, sem Docker, PostgreSQL 11.3, sem Celery, sem DRF, com os arquivos de deploy para o Heroku. O resto ficou no padrão.
Instalando as dependências e criando o banco
Entre na pasta do projeto e instale os requirements de desenvolvimento (o local.txt inclui o base.txt e acrescenta debug toolbar, pytest, linters etc.):
cd myproject
pip install -r requirements/local.txt
O projeto usa PostgreSQL. Se você rodar o migrate antes de criar o banco, dá erro:
python manage.py migrate
django.db.utils.OperationalError: FATAL: database "myproject" does not exist
Então crie o banco (considerando que o PostgreSQL já está instalado e que existe o usuário postgres) e rode o migrate de novo:
createdb myproject -U postgres
python manage.py migrate
Rodando
python manage.py runserver
Em http://localhost:8000 aparece o site com o menu Home, About, Cadastro e Entrar, e a barra lateral do Django Debug Toolbar.
O cadastro de usuários (feito com o django-allauth) já funciona, com confirmação de e-mail:
- Clique em Cadastro e preencha e-mail, nome de usuário e senha.
- Em desenvolvimento o e-mail não é enviado de verdade: ele aparece no terminal onde está o
runserver, com o link de confirmação, algo comohttp://localhost:8000/accounts/confirm-email/MQ:1jkKe.../. - Abra o link e confirme o e-mail ("Confirmou rg3915@example.com").
- Agora é só Entrar com o usuário e a senha. Logado, aparecem My Profile e Sair.
Resumo
boilerplatesimple.sh: o mínimo, um projeto comsettings.pyorganizado (decouple + dj-database-url) e um appcorevazio.boilerplate2.sh: um projeto de exemplo completo, com CRUD de contatos, testes e dados.cookiecutter-django: um projeto pronto para produção, com PostgreSQL, autenticação com allauth e muitas opções.
Os comandos do cookiecutter-django, de uma vez:
python -m venv .venv
source .venv/bin/activate
pip install "cookiecutter>=1.7.0"
cookiecutter https://github.com/pydanny/cookiecutter-django
pip install -r requirements/local.txt
python manage.py migrate
createdb myproject -U postgres
python manage.py migrate
Observação: o cookiecutter-django mudou de endereço para github.com/cookiecutter/cookiecutter-django (o link antigo redireciona) e hoje usa versões bem mais novas do Django, com outras perguntas. O django-admin.py usado pelos scripts deixou de existir no Django 4.0; nas versões novas o comando é django-admin.