[PARTE-1][TUTORIAL][DEPLOY][DJANGO] - Enviando para deploy
Orientações
Para o deploy usarei minha VPS/Domínio comprados no site da HOSTINGER , para quem quiser me ajudar comprando com o meu cumpom HOSTINGER - REFERÊNCIA, caso você compra sua VPS e seu domínio, ou qualquer outro produto dentro do site, utilizando meu código, vai me ajudar a receber uma graninha a mais.
Na hostinger eles oferecem o aplicativo para deploy de varias aplicações, como django, rusty, node entre outras, usando o OpenLiteSpeed como gerênciador.
Muitas vezes tentei fazer deploy com NGINX, porém é muito trabalhoso.
Usaremos também POSTGRESSQL, caso queira usar SQLITE apenas pule as etapas indicadas.
Início
Escolha um diretório e vamos começar, usarei o GitBash para começar o projeto.
$ mkdir django-project
$ cd django-project
$ nano .env
#ADICIONAR AO ARQUIVO E SALVAR
SECRET_KEY=!r8!9ja-3jl*_@5f*3uz4#byytvets90tj9g_9w(t$!_^7!l3j
DEBUG=True
POSTGRES_NAME=django_project_db
POSTGRES_USER=django_project_user
POSTGRES_PASSWORD=!r8!9ja-3jl*_@5f*3uz4#byytvets90tj9g_9w(t$!_^7!l3j
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
$ python -m virtualenv venv
$ source venv/Scripts/activate
$ pip install django python-dotenv whitenoise psycopg2-binary Pillow
Criando o projeto, eu sempre crio primeiro a pasta no caso django-project e depois dentro eu uso o django-admin com um "." na frente para criar no mesmo diretório
$ django-admin startproject core .
$ mkdir apps
$ cd apps
$ django-admin startapp accounts
$ cd accounts
$ nano urls.py
#ADICIONAR AO ARQUIVO E SALVAR
from django.urls import static
urlpatterns = [
]
Sempre tive dúvida de como utilizar os apps do django em uma pasta especifica, é simples, no arquivo "apps.py", adicione a frente do name='accounts', o "apps." ou o nome da pasta desejada.
from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.accounts'
Em settings, vamos fazer uma jogada, segue as pastas em forma de árvore.
TREE MAKER
.
└── django-project/
├── apps/
│ └── accounts
├── core/
│ └── settings/
│ ├── __init__.py
│ ├── base.py
│ ├── local.py
│ └── production.py
├── templates
├── static/
│ ├── css
│ ├── js
│ └── images
├── media
├── public/
│ ├── static
│ └── media
├── .env
└── .gitignore
Settings
Para que funcione o settings precisamos alterar alguns arquivos do django (WSGI e manage)
manage.py
import os
import sys
from core.settings import base
def main():
"""Run administrative tasks."""
if base.DEBUG:
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'core.settings.local')
else:
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'core.settings.production')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
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?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
wsgi.py
import os
from core.settings import base
from django.core.wsgi import get_wsgi_application
if base.DEBUG:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings.local')
else:
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'core.settings.production')
application = get_wsgi_application()
base.py
- Aqui vou configurar também o whitenoise, para servir os staticfiles em produção na pasta public/static e media e também o BASE_DIR , muito importante.
...
import os
from dotenv import load_dotenv
load_dotenv()
#O PADRÃO É VIR COM 2 PARENTS , PORÉM VAMOS COLOCAR MAIS UM
BASE_DIR = Path(__file__).resolve().parent.parent.parent
...
SECRET_KEY = os.environ.get('SECRET_KEY')
DEBUG = os.environ.get('DEBUG') == 'True'
ALLOWED_HOSTS = ['*']
#OPICIONAL CASO QUEIRA USAR O CODESPACE PARA EDITAR SEU PROJETO
if 'CODESPACE_NAME' in os.environ:
codespace_name = os.getenv("CODESPACE_NAME")
codespace_domain = os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN")
CSRF_TRUSTED_ORIGINS = [
f'https://{codespace_name}-8000.{codespace_domain}']
X_FRAME_OPTIONS = "ALLOW-FROM preview.app.github.dev"
#ADIÇÃO DO APP DE ACCOUNTS
INSTALLED_APPS = [
...,
"apps.accounts",
]
#CONFIGURAÇÃO DO WHITENOISE
MIDDLEWARE = [
# ...
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
# ...
]
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
]
LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'
#PARA SERVIR OS ARQUIVOS STATICOS, VAMOS USAR AS CONFIGURAÇÕES A SEGUIR
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
STATIC_URL = '/public/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'public/static')
MEDIA_URL = '/public/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'public/media')
#MODELO DE AUTENTICAÇÃO EDITADO
AUTH_USER_MODEL = 'accounts.Account'
local.py
- No local, vamos utilizar o sqlite para facilitar as configurações, pode retirar o DATABASES do base.
from .base import *
DEBUG = True
ALLOWED_HOSTS = [
'*',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
production.py
- As configurações são necessárias para melhor segurança da sua aplicação.
from .base import *
DEBUG = False
#COLOCAR SEU HOST AQUI
ALLOWED_HOSTS = [
'*'
]
#SEGURANÇA
if os.environ.get("DEBUG") == False:
# SECURITY WARNING: don't run with debug turned on in production!
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 3600
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
X_FRAME_OPTIONS = "DENY"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ.get("POSTGRES_NAME"),
"USER": os.environ.get("POSTGRES_USER"),
"PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
"HOST": os.environ.get("POSTGRES_HOST"),
"PORT": os.environ.get("POSTGRES_PORT"),
}
}
Configurando os static files
core/urls.py
from django.contrib import admin
from django.urls import path,re_path,include
from django.conf.urls.static import static
from django.conf import settings
from django.views.static import serve
urlpatterns = [
path('admin/', admin.site.urls),
]
#INCLUDES
urlpatterns += [
# INCLUDES
path('', include('apps.accounts.urls')),
]
#STATICFILES
urlpatterns += [
# STATICMEDIA SERVE
re_path(r'^public/media/(?P<path>.*)$', serve,
{'document_root': settings.MEDIA_ROOT}),
re_path(r'^public/static/(?P<path>.*)$', serve,
{'document_root': settings.STATIC_ROOT}),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Criando o modelo de accounts
models.py
import uuid
from django.db import models
from django.contrib.auth.models import AbstractUser
def image_path(instance, filename):
ext = filename.split('.')[-1]
filename = f'{uuid.uuid4()}.{ext}'
user= Account.objects.get(email=instance)
return f"accounts/{user.username}/avatars/{filename}"
class Account(AbstractUser):
email = models.EmailField(
max_length=255, unique=True, blank=False, null=False)
avatar = models.ImageField(
upload_to=image_path, blank=True, null=True)
email_notify = models.BooleanField("Notificação por email", default=True)
slug = models.SlugField(blank=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.username
return super().save(*args, **kwargs)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username',]
def __str__(self):
return self.email
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.html import format_html
from apps.accounts.models import Account
# Register your models here.
@admin.register(Account)
class AccountAdmin(UserAdmin):
def thumbnail(self, object):
return format_html(
"<img src='{}' width='30' height='30' style='border-radius:50%;'/>"
.format(object.avatar.url))
model = Account
list_display = ('id', 'email', 'username', 'last_login',
'date_joined', 'is_active')
list_filter = ('email', 'username', 'last_login',
'date_joined', 'is_active')
readonly_fields = ('last_login', 'date_joined', "slug")
fieldsets = (
('Configurações', {
"fields": ("avatar", "email", "password", "email_notify")}),
("Permissões", {"fields": ("is_superuser", "is_staff",
"is_active", "groups", "user_permissions")}),
("Datas importantes", {"fields": ("date_joined", "last_login")}),
("Imutáveis", {"fields": ("slug",)})
)
add_fieldsets = (
(None, {
"classes": ("wide",),
"fields": (
"email", "password1", "password2", "is_staff",
"is_active", "groups", "user_permissions"
)}
),
)
search_fields = ('email', 'first_name', 'last_name', 'username')
ordering = ('-date_joined',)
Iniciando as migrações e criação do superuser
Em sua pasta inicial django-project
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
Usando o navegador, acessar http://127.0.0.1:8000/admin/ , verificar se tudo está funcionando.
Após a criação da autenticação de usuários, podemos seguir adiante.
Vamos dar continuidade em um próximo post, deixa sua mensagem pra gente continuar.