Django Básico
===
###### tags: `python, django, python web`
# Preparando o Ambiente
Download do interpretador do Python para windows:
* https://www.python.org/
Documentação:
* https://www.python.org/doc/
Teste de código Python via web:
* http://pythontutor.com
# Configurações Iniciais
### Instalando Django
Criar uma uma venv, ambiente virtual.
Colocar o código no CMD dentro da pasta da aplicação:.
```a
python3 -m venv ./venv
```
Ou apenas:
```a
python -m venv ./venv
```
Para carregar a venv, e iniciar o ambiente virtual, o caminho precisa ser completo:.
```a
C:\Users\seu_usuario\pasta_da_aplicacao\venv\Scripts\activate
```
Instalar o Django no projeto com a venv iniciada:
```a
pip install django==2.2.12
```
### Iniciando o projeto
Para criar uma pasta do projeto:
>O "." no final serve para que crie o projeto como pasta principal e não que crie outra pasta com o nome do projeto.
>
```a
django-admin startproject nome_proejeto .
```
### Iniciando um app
Um App faz parte do projeto, uma aplicação com determindada função.
Iniciando um app:
```a
python manage.py startapp nome_do_app
```
### Alterando o idioma e horário
Mude a lingua e timezone do Django no arquivo setting.py, por volta da linha 106 e 108:
```a
LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'
```
### CollectStatic
Ajuda a criar uma coleção dos arquivos de CSS, JS, imagens, usado quando vamos enviar o sistema para produção:
```a
python manage.py collectstatic
```
Configuração em setting.py:
```a
#em desenvolvimento
STATIC_URL = '/static/'
STATICFILES_DIRS=[
os.path.join(BASE_DIR, 'pasta_projeto/static')
]
#em produção
STATIC_ROOT = os.path.join(BASE_DIR,'static')
```
### Mensagem de Erro
Em settings.py, ao final do arquivo acrescentar:
```a
from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.ERROR: 'danger',
messages.SUCCESS: 'success',
}
```
No arquivo de views.py do app:
```a
if condicao:
messages.error(request, 'Mensagem a ser exibida ao usuário')
return redirect('pagina')
```
Por convenção é criado um partials com o nome "_alerta.html" com o código:
```a
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{message.tags}}" role="alert">
{{message}}
</div>
{% endfor %}
{% endif %}
```
No caso utilizei o Bootrstrtap 4 com classe de erro, para criar a mensagem.
### Models
Arquivo de models.py:
```a
from django.db import models
from django.db.models import signals
from django.template.defaultfilters import slugfy
class Base(models.Model):
criado = models.DateField('Data de Criação', auto_now_add=True)
#salva quando foi criado
modificado = models.DateField('Data de Alteração', auto_now=True)
#salva quando foi alterado
ativo = models.BooleanField('Ativo',default=True)
class Meta:
abstract = true
# A classe abstrata ela não será criada direto no banco.
# Irá servir de base para outras classes.
class Produto(Base): # A classe produto herda de base
nome = models.CharField('Nome', max_length=100)
preco = models.DecimalField('Preço', max_digits=8, decimal_places=2)
estoque = models.IntegerField('Estoque')
slug = models.SlugField('Slug', max_length=100, blank=True, editable=False)
#caso algum valor possa ser vazio "null=True", declarar como opção
def __str__(self):
return self.nome
def produto_pre_save(signal, instance, sender, **kwards):
instance.slug = slugify(instance.nome)
signals.pre_save.connect(produto_pre_save, sender=Produto)
#quando produto for enviado, o signals ele é ativo
#slugify serve para pegar o nome do produto e transformar em slug.
#Exemplo: Pé de Moleque => pe-de-moleque
#Esse método serve para criar urls com o nome do produto.
#Exemplo: http://site.com/pe-de-moeleque
```
### Utilizando o Admin do DJango
Na pasta da aplicacação, terá um arquivo com o nome admin.py, para utilizar o CRUD dele através do painel administrativo do Django, basta configurar da seguinte forma:
```a
from django.contrib import admin
from .models importe Nome_das_Classes1,Nome_das_Classes2
@admin.register(Nome_da_Classe)
class Nome_das_ClassesAdmin(admin.ModelAdmin):
list_display=('nome_da_tabela_1','nome_da_tabela_2','nome_da_tabela_3')
```
### Forms do Django
# Utilidades
### Blibliotecas
#### MatchFilter
Documentação: https://pypi.org/project/django-mathfilters/
Instala a biblioteca MathFilters, para fazer calcúlos no template:
`pip install django-mathfilters`
Precisa declarar em INSTALLED_APPS, em settings.py da aplicação.
Declarar no template:
```a
{% load mathfilters %}
```
Exemplos:
```a
<ul>
<li>8 + 3 = {{ 8|add:3 }}</li>
<li>13 - 17 = {{ 13|sub:17 }}</li>
{% with answer=42 %}
<li>42 * 0.5 = {{ answer|mul:0.5 }}</li>
{% endwith %}
{% with numerator=12 denominator=3 %}
<li>12 / 3 = {{ numerator|div:denominator }}</li>
{% endwith %}
<li>|-13| = {{ -13|abs }}</li>
</ul>
```
#### Boostrap4
Já adicona o framework boostrap 4 na aplicação.
```a
pip install django-bootstrap4
```
Em settings.py, precisa declarar em APPS_INSTALED
`'boostrap4',`
#### Envio de E-mail
Deve ser declarado no final do arquivo de settings.py da aplicação.
Printa o e-mail no console:
```a
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
```
Caso o servidor de hospedagem possua um servidor de e-mail, usar as configurações abaixo:
```a
EMAIL_HOST = 'localhost' #geralmente
EMAIL_HOST_USER = 'no-reply@seudominio.com.br' #geralmente
EMAIL_HOST_PASSWORD = 'sua_senha'
EMAIL_PORT = 587 #geralmente, para conexão segura
EMAIL_HOST_TSL = True #pode ser que tenha
```
Na view:
```a
from django.core.email.message import EmailMenssage
def mandar_email(request):
if request.method == 'POST':
nome = request.POST['nome']
email = request.POST['email']
assunto = request.POST['assunto']
conteudo = f'Nome:{nome}\n E-mail:{email}\n Assunto:{assunto}'
mail = EmailMenssage(
subject='E-mail enviado pelo sistema!',
body=conteudo,
from_email='contato@seu_dominio.com.br',
to=['contato@email.com.br','outro_email@email.com'],
headers={'Reply-To:email'}
#esse email vem do post, ele é pra quem irá responder
)
mail.send()
```
### CRUD com Imagens
Documentação: https://pypi.org/project/django-stdimage/
Instale a biblioteca para trabalhar com imagens.
```a
pip install django-stdimage
```
#### No arquivo models.py da aplicação:
```a
from stdimage import StdImageField, JPEGField
imagem = StdImageField('Imagem', upload_to='nome_da_pasta', variations={'thumb':(124,124)})
#variations cria um arquivo com o tamanho nome já pré definido, no caso 'thumb'
#també pode ser declarado em models.py:
imagem = models.ImageField(upload_to='nome_da_pasta/%d/%m/%Y',blank=True)
```
#### Insert no arquivo de views.py:
```a
def nome_do_metodo(request):
if request.method == 'POST':
imagem = request.FILES['nome_no_input_form']
produto = Produto.objects.create(nome_no_banco=imagem)
produto.save()
```
#### Update no arquivo de views.py:
```a
def nome_do_metodo(request):
if request.method == 'POST':
produto_id = request.POST['produto_id']
p = Produto.objects.get(pk=produto_id)
#pega todas as informaçoes de produto do banco
if 'imagem' in request.FILES:
r.nome_no_banco = request.FILES['nome_no_input_form']
p.save()
```
### Conexão PostgreSQL
Instale a biblioteca para conexão.
```a
pip install psycopg2
```
Módulo para banco postgre.
```a
pip install psycopg2-binary
```
No settings.py.
```a
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'nome_do_banco',
'USER': 'usuario',
'PASSWORD': 'senha',
'HOST': 'localhost'
}
}
```
### Conexão MySQL
Instale a biblioteca para conexão.
```a
pip install PyMySQL
```
Módulo para banco postgre.
```a
pip install MySQL
```
No settings.py.
```a
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'nome_do_banco',
'USER': 'usuario',
'PASSWORD': 'senha',
'HOST': 'localhost',
'PORT': '3306', #porta padrão do MySQL
}
}
```
### Redirect ao deslogar
Ao final do arquivo settings.py.
Força um 'redirect' ao usuário quando deslogar, para a página desejada:
```a
LOGOUT_REDIRECT_URL = 'login'
```
### Página de Erros
Importar django.conf.url no início de settings.py:
```a
from django.conf.urls import handler400 #requisição não irá ser processada pela má formulação da requisição
from django.conf.urls import handler403 #sem premissão ou acesso negado a parte do sistema
from django.conf.urls import handler404 #objeto perdido ou não encontrado
from django.conf.urls import handler500 #dificuldade de processamento do servidor, a partir de uma incompatibilidade ou configuração incorreta
```
Importar também a localização de onde se encontra a view resposável pelo controle:
```a
from app_da_view import views
```
Ao final do arquivo settings.py:
```a
handler404 = views.error404
```
Código na view:
```a
from django.http import HttpResponse
from django.shortcuts import render
def error404(request,excption):
from django.template import loader
template = loader.get_template('404.html')
return HttpResponse(content=template.render(), content_type='text/html; charset=utf8', status=404)
```
### Comandos Para Aplicação
Iniciar o servidor:
```a
python manage.py runserver
```
Caso esteja utiliazando o Visual Code, assim sempre que abrir uma nova aba do CMD já vai abrir com oo venv:
```a
CTRL+SHIFT+P > python: select interpreter > selecionar o interpretador venv/venv
```
Cria um arquivo com os requerimentos da aplicação
```a
pip freeze > requirements.txt
```
### Comandos Para Banco
Faz as migrações para a aplicação:
```a
python manage.py makemigrations
```
Faz as migrações para o banco:
```a
python manage.py migrate
```
Deleta o banco de dados (CUIDADO AO USAR!):
```a
python manage.py flush
```
Faz o model com as tabelas presentes no banco:
```a
python manage.py inspectdb
```
Zera as migrações já feitas, igual um delete:
```a
python manage.py migrate "nome_do_banco_para_zerar" zero
```
# Deploy da Aplicação no Heroku
Digitar no terminal:
```a
pip install whitenoise gunicorn
```
Whitenoise => biblioteca para o django exibir os arquivos estáticos
Gunicorn => biblioteca serve como servidor para rodar o python
Adiconar o Whitenoise em MIDDLEWARE no arquivo settings.py:
```a
'whitenoise.middleware.WhiteNoiseMiddleware',
```
Criar um arquivo na raiz do projeto chamado ".gitignore", com os seguintes parâmetros:
```a
__pycache__
*.*~
*.pyc
.idea
```
No arquivo settings.py:
A opção 'DEBUG' precisa estar como falso, mostrando que a aplicação irá para um amabiente de produção.
Em 'ALLOWED_HOSTS', precisa ser o host da aplicação, quando não sabemos, basta colocar o '*', que irá funcionar com qualquer endereço.
```a
DEBUG = False
ALLOWED_HOSTS = ['*']
```
---
Digitar os comandos no terminal:
` git init => inicia o GIT`
` git status => mostra os arquivos que não foram adicionados`
` git add . => adicona todos os arquivos`
` git commit -m "Nome do Projeto" => Cria um branch com o nome desejado`
Caso seja a primeira vez precisa fazer o login:
```a
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
```
Servidor usado será o Heroku, precisa baixar o cliente no link abaixo.
https://devcenter.heroku.com/articles/getting-started-with-python#set-up
Criar um arquivo na raiz do projeto "runtime.txt"
Precisa saber qual a versão do python está utilizando, digite no terminal `python -V`
Adiconar a versão python no runtime.txt `python-3.8.3`
>Essa é a minha versão do python
Atualizar o requirements.txt
` pip freeze > requirements.txt`
Criar um Arquivo na raiz do projeto "Procfile" do tipo "Text"
No arquivo Procfile digitar:
```a
web: gunicorn nome_projeto.wsgi --log-file -
```
>Precisa dizer em qual diretório está o arquivo "WSGI.PY"
---
Fazer o login no heroku através do terminal:`heroku login`
Ao abrir a janela do navegador, faça o login.
>As vezes no primeiro login pode dar erro, apenas refaça a operação.
>
Criando primeiro projeto no Heroku:
`heroku create nome_do_projeto_unico --buildpack heroku/python`
>Muito Importante! O nome do projeto precisa ser único devido a URL.
Apoós criar o projeto, deve passar os arquivos que estão no git.
`git push heroku master`
## Deploy com Banco de Dados
O banco precisa estar no requirements.txt.
Ao dar o push ao heroku, precisa rodar o comando:
`heroku run python manage.py migrate`
Criar o superuser:
`heroku run python manage.py createsuperuser`
## Deploy com Imagens
Usando a conta gratuita do Heroku, não tem como usar o Nginx para exibir as imagens. Então uma outra biblioteca tera que ser usada no lugar do WhiteNoise.
Baixar:
`pip install dj-static`
Removendo o WhiteNoise:
`pip unistall whitenoise`
Remover também do MIDDLEWARE em settings.py
Rodar o arquivo de requirements.txt, para instalar tudo:
`pip install -r requirements.txt`
Atualizar o arquivo de requirements.txt:
`pip freeze > requirements.txt`
No arquivo wsgi.py;
```a
import os
from django.nome_do_projeto.wsgi import get_wsgi_application
from dj_static import Cling, MediaCling
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'nome_do_projeto.settings')
application = Cling(MediaCling(get_wsgi_application()))
```
---