Python

Enviando email com Python e SMTP

O envio de emails é a melhor forma para se comunicar com os usuários de uma aplicação. Além de ser gratuito (na maioria das vezes), é seguro e muito utilizado em todo o mundo.

Pensando nisso, veremos neste artigo como enviar e-mails em aplicações Python utilizando SMTP.

Configurando servidor gmail

Em nosso exemplo, veremos como enviar um email utilizando o serviço do gmail (pois ele é o mais utilizado no mundo). Porém, antes de iniciar o desenvolvimento do nosso projeto, precisamos criar um token para ser utilizado como password, caso você utilize o recurso de autenticação em duas etapas (recurso que só permite que seu usuário seja autenticado caso você o libere em seu smartphone) ou não quer que sua senha seja utilizada em aplicações não seguras.

Criando token

Para criar um token que será utilizado como senha em nossa aplicação, precisamos ir até o seguinte link: https://security.google.com/settings/security/apppasswords.

Na página, vamos selecionar a opção “Outro” para definir um nome para nosso projeto. Em seguida, determinamos o nome da aplicação e geramos o token:

Ao clicar em “GERAR”, seremos redirecionados para a tela de login da nossa conta. Ao inserir o email e senha, clicamos em “Próxima” e nosso token será gerado com sucesso:

É essa “senha de app” que vamos utilizar para autenticar com nosso gmail na aplicação (lembre-se de copiá-la).

Criando script para envio de email

Nosso script será bem simples. Basicamente, vamos informar o email e senha (conforme gerada no tópico anterior) da conta que será usada para enviar o email, o destinatário e o conteúdo do email. Sendo assim, o código final será o seguinte:

import smtplib

server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login("seu_email@gmail.com", "senha_gerada_topico_anterior")
server.sendmail(
  "remetente@gmail.com",
  "destinatario@gmail.com",
  "Conteúdo da mensagem")
server.quit()

Basicamente, o código acima irá criar uma conexão com o serviço de SMTP do gmail por meio da porta 456, realizar o login com as credenciais do usuário e enviar o email conforme os parâmetros enviados pelo método sendmail(). Ao concluir o processo, finalizamos o servidor e o email deve chegar no destinatário.

Sendo assim, ao executar o código acima (você pode utilizar qualquer editor de texto, IDE ou terminal), o email será enviado com sucesso, chegando até o destinatário:

Conclusão

Neste artigo vimos o quão simples é enviar um email utilizando Python. Claro que há várias melhorias que podemos fazer (adicionar o assunto do email, enviar um código HTML como conteúdo do email), mas isso nós veremos em um outro artigo 🙂

Implementando autenticação no Django – Parte 2

Continuando a implementação do módulo de autenticação em uma aplicação Django que iniciamos no artigo “Implementando autenticação no Django – Parte 1“, veremos neste artigo como implementar os métodos de logout, alterar senha do usuário e proteger páginas para que só sejam acessadas por usuários devidamente autenticados.

Logout

A principal função do método de logout é remover a sessão do usuário que está logado na aplicação, fazendo com que este login não esteja mais ativo no sistema. Assim como o método de login, o Django possui, em seu módulo de autenticação, o método para deslogar usuários. Para implementá-lo, basta criar um método no arquivo views.py com o seguinte conteúdo:

def deslogar_usuario(request):
    logout(request)
    return redirect('index')

Basicamente, o médoto deslogar_usuario recebe uma requisição e remove o usuário que está logado dela. Simplesmente assim 🙂

Agora, para acessar o método de deslogar_usuario, precisamos criar sua rota no arquivo urls.py da aplicação:

from django.contrib import admin
from django.urls import path, include
from .views import *

urlpatterns = [
    path('logar_usuario', logar_usuario, name="logar_usuario"),
    path('deslogar_usuario', deslogar_usuario, name="deslogar_usuario"),
    path('cadastrar_usuario', cadastrar_usuario, name="cadastrar_usuario"),
    path('index', index, name="index"),
]

Com isso, ao acessar a rota http://localhost:8000/deslogar_usuario, a sessão será destruída e o usuário deslogado do nosso projeto.

Alterar senha do usuário

Uma outra funcionalidade importante para um sistema de autenticação é o método para alterar senha do usuário logado. Com o Django, esta implementação é bem simples.

Primeiro, vamos criar um método alterar_senha no arquivo views.py do projeto com o seguinte conteúdo:

def alterar_senha(request):
    if request.method == "POST":
        form_senha = PasswordChangeForm(request.user, request.POST)
        if form_senha.is_valid():
            user = form_senha.save()
            update_session_auth_hash(request, user)
            return redirect('index')
    else:
        form_senha = PasswordChangeForm(request.user)
    return render(request, 'alterar_senha.html', {'form_senha': form_senha})

Basicamente, este método irá criar um PasswordChangeForm vazio para que o usuário que estiver logado digite as informações necessárias para alteração de senha (senha antiga, nova senha e confirmação da nova senha). Depois que o usuário submeter o formulário, verificamos se ele é válido e, caso positivo, alteramos a senha do usuário com o método update_session_auth_hash e redirecionamos para a página index da aplicação.

Para que o usuário consiga digitar as informações necessárias para alterar sua senha, criaremos um template chamado alterar_senha no diretório templates da nossa aplicação. Ele é bem simples, apenas renderizamos os inputs necessários para esta funcionalidade:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Alterar senha</title>
</head>
<body>

<form method="post">
    {% csrf_token %}

    <div class="form-group">
        {{form_senha.old_password.errors}}
        <label>Senha antiga: </label>
        {{form_senha.old_password}}
    </div>

    <div class="form-group">
        {{form_senha.new_password1.errors}}
        <label>Nova senha: </label>
        {{form_senha.new_password1}}
    </div>

    <div class="form-group">
        {{form_senha.new_password2.errors}}
        <label>Confirmação de senha: </label>
        {{form_senha.new_password2}}
    </div>

    <div class="form-group">
        <input type="submit" value="Alterar" class="btn btn-primary">
    </div>
</form>

</body>
</html>

Por fim, precisamos criar a rota responsável por executar o método alterar_senha. Para isso, no arquivo urls.py da aplicação, adicionamos a seguinte linha no array urlpatterns:

    path('alterar_senha/', alterar_senha, name='alterar_senha'),

Com isso, ao acessar a rota http://localhost:8000/alterar_senha, veremos o seguinte resultado:

É por meio desta página que o usuário poderá alterar sua senha na aplicação.

Proteger páginas

Sabemos que a principal vantagem de implementar a autenticação em nossas aplicações é a de proteger páginas e recursos para que apenas usuários devidamente autenticados possam acessá-las. Para isso, só precisamos adicionar o decorator login_required nos métodos que queremos proteger:

@login_required(login_url='/logar_usuario')
def index(request):
    return render(request, 'index.html')

@login_required(login_url='/logar_usuario')
def deslogar_usuario(request):
    logout(request)
    return redirect('index')

@login_required(login_url='/logar_usuario')
def alterar_senha(request):
    if request.method == "POST":
        form_senha = PasswordChangeForm(request.user, request.POST)
        if form_senha.is_valid():
            user = form_senha.save()
            update_session_auth_hash(request, user)
            return redirect('index')
    else:
        form_senha = PasswordChangeForm(request.user)
    return render(request, 'alterar_senha.html', {'form_senha': form_senha})

Agora, ao tentar acessar as páginas para alterar senha, deslogar usuário e index, o Django irá verificar se existe algum usuário logado e, caso contrário, redirecionará para a página de login.

Conclusão

Nesta série de artigo, vimos o quão fácil é implementar os principais recursos de autenticação com o Django. A autenticação é a melhor forma de garantir que os recursos de um projeto só sejam acessados por usuário previamente cadastrados e autenticados, garantindo uma maior segurança do projeto.

Lembrando que o código-fonte deste projeto se encontra neste repositório

Implementando autenticação no Django – Parte 1

A autenticação é uma das principais funcionalidades em um sistema. É com ela que protegemos as funcionalidades de uma aplicação e permitimos que estas só sejam acessadas por usuários cadastrados e autenticados previamente.

O Django possui um módulo de autenticação extremamente completo e fácil de implementar, como veremos neste artigo.

Para a construção deste projeto, vamos iniciá-lo apenas com uma página index que exibirá uma mensagem “Página protegida”. É ela quem vamos restringir para que apenas usuários autenticados possuam acesso.

Lembrando que este projeto está neste repositório.

Cadastrando usuários

Para autenticar os usuários, primeiro precisamos cadastrá-los no banco de dados. O Django possui, em seu módulo de segurança, toda uma base para este cadastro. Para utilizá-la, vamos até o arquivo views.py da nossa aplicação e criamos o seguinte método:

def cadastrar_usuario(request):
    if request.method == "POST":
        form_usuario = UserCreationForm(request.POST)
        if form_usuario.is_valid():
            form_usuario.save()
            return redirect('index')
    else:
        form_usuario = UserCreationForm()
    return render(request, 'cadastro.html', {'form_usuario': form_usuario})

O método acima é bem simples. Basicamente, ele cria uma instância do UserCreationForm passando todos os dados da requisição (dados do usuário a ser cadastrado no BD), verifica se estes dados são válidos e os persiste no banco de dados.

Lembrando que o UserCreationForm é um Form do próprio Django utilizado para cadastrar usuários no projeto.

Para que os dados sejam cadastrados, precisamos de um template para interagir com o usuário da aplicação. Sendo assim, o arquivo cadastro.html foi criado com o seguinte conteúdo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Cadastro de usuários</title>
</head>
<body>

<form method="post">
    {% csrf_token %}

    <div class="form-group">
        {{form_usuario.username.errors}}
        <label>Username: </label>
        {{form_usuario.username}}
    </div>

    <div class="form-group">
        {{form_usuario.password1.errors}}
        <label>Senha: </label>
        {{form_usuario.password1}}
    </div>

    <div class="form-group">
        {{form_usuario.password2.errors}}
        <label>Confirmação de senha: </label>
        {{form_usuario.password2}}
    </div>

    <div class="form-group">
        <input type="submit" value="Cadastrar" class="btn btn-primary">
    </div>
</form>

</body>
</html>

O template possui apenas um formulário com os dados que um usuário deve possuir para salvá-lo no banco de dados do projeto (username e password).

Além disso, precisamos definir uma rota para o usuário conseguir acessar o formulário. Para isso, no arquivo urls.py, definimos o seguinte conteúdo:

from django.contrib import admin
from django.urls import path, include
from .views import *

urlpatterns = [
    path('cadastrar_usuario', cadastrar_usuario, name="cadastrar_usuario"),
    path('index', index, name="index"),
]

Agora, ao acessar a rota /cadastrar_usuario, o seguinte formulário será renderizado:

Ao preencher o formulário e submetê-lo, um novo usuário será criado no banco de dados do projeto, mais especificamente na tabela auth_user:

Podemos notar que o usuário foi salvo com sucesso e que sua senha foi criptografada utilizando o sha256. Além disso, o usuário joao12 ainda não se autenticou na aplicação (o que vamos fazer no próximo tópico) e que há algumas informações em branco (first_name e email), já que estas não são obrigatórias no projeto.

Agora, precisamos utilizar estas informações no banco de dados e autenticar os usuários em nossa aplicação.

Autenticando usuários

Após cadastrar os usuários no banco de dados do projeto, vamos utilizar estas informações para autenticá-los. Para isso, o primeiro passo é criar o template (login.html) onde o próprio usuário poderá preencher com seus dados de login:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
    {% csrf_token %}

    <div class="form-group">
        {{form_login.username.errors}}
        <label>Username: </label>
        {{form_login.username}}
    </div>

    <div class="form-group">
        {{form_login.password.errors}}
        <label>Senha: </label>
        {{form_login.password}}
    </div>

    <div class="form-group">
        <input type="submit" value="Enviar" class="btn btn-primary">
    </div>
</form>
</body>
</html>

O formulário de login é bem simples. Precisamos apenas dos campos username e password para autenticar um usuário no banco de dados. De posse dessas informações, enviamos a requisição para o método logar_usuario do arquivo views.py do projeto, que capturará estes dados e logará o usuário na aplicação (caso os dados estejam corretos):

def logar_usuario(request):
    if request.method == "POST":
        username = request.POST["username"]
        password = request.POST["password"]
        usuario = authenticate(request, username=username, password=password)
        if usuario is not None:
            login(request, usuario)
            return redirect('index')
        else:
            form_login = AuthenticationForm()
    else:
        form_login = AuthenticationForm()
    return render(request, 'login.html', {'form_login': form_login})

O método logar_usuario é bem simples. Ele irá capturar os dados enviados por meio do formulário e os utilizará para autenticar um novo usuário por meio do método authenticate do Django.

Este método irá verificar se os dados de login estão corretos (de acordo com os dados presentes no banco de dados) e salvar a resposta na variável usuario. Há dois retornos possíveis para o método authenticate: None, se os dados informados estiverem incorretos, e o usuário, caso os dados estejam corretos.

Verificamos este retorno e, caso o usuário exista no banco de dados, utilizamos o método login para logá-lo na aplicação. A partir daí, este usuário estará autenticado no projeto 🙂

Lembrando que precisamos criar a rota responsável por executar o método logar_usuario no arquivo views.py:

from django.contrib import admin
from django.urls import path, include
from .views import *

urlpatterns = [
    path('logar_usuario', logar_usuario, name="logar_usuario"),
    path('cadastrar_usuario', cadastrar_usuario, name="cadastrar_usuario"),
    path('index', index, name="index"),
]

Agora, ao acessar a rota localhost:8000/logar_usuario, o formulário de login será exibido para que possamos informar as credenciais do usuário e autenticá-lo na aplicação:

Notem que o campo last_login foi preenchido com a data e hora do último login do usuário (o id do usuário mudou porque tinha esquecido sua senha, então tive que recriá-lo 😛 )

Com isso, já estamos com os métodos de login e cadastro de usuários prontos e funcionais. O próximo passo é incrementar nosso módulo de autenticação, adicionando os métodos de logout, alterar senha e proteger páginas para que apenas usuários logados possuam acesso, mas isso nós vamos fazer nos próximos artigos desta série de autenticação com Django. Até lá 🙂

Principais comandos do Django CLI

Quando estamos iniciando os estudos com o Django, é bem comum esquecermos os principais comandos para gerenciar nossa aplicação (executar o servidor de desenvolvimento, criar um projeto, criar uma aplicação, criar migrações, etc). Pensando nisso, neste artigo veremos quais são os comandos responsáveis por cada uma das principais funcionalidades do CLI do Django.

Criar Projeto

Para criar um projeto no Django, utilizamos o seguinte comando no terminal:

django-admin startproject nome_do_projeto

Este comando irá criar um projeto Django vazio, com a estrutura de arquivos e diretórios padrão do framework.

Criar Aplicação

Após criar um projeto, precisamos criar uma (ou mais) aplicações para o projeto. Para isso, utilizamos o seguinte comando:

python manage.py startapp nome_da_app

Lembrando que este comando deverá ser executado no mesmo diretório em que se encontra o arquivo manage.py do projeto, ou seja, dentro do diretório padrão do projeto que estamos criando.

Django - Fundamentos
Curso de Django - Fundamentos
CONHEÇA O CURSO

Criar Migrações

Após determinar quais serão as entidades que utilizaremos em nosso projeto, precisamos criar as tabelas que representam estas entidades no banco de dados. Para isso, utilizamos o seguinte comando:

python mananage.py makemigrations

O comando acima irá obter a estrutura das classes definidas no arquivo models.py e criará os arquivos de migração de cada classe.

Executar Migrações

Após criar os arquivos que definem a estrutura de cada entidade no banco de dados, precisamos executar estas migrações. Para isso, utilizamos o seguinte comando:

python manage.py migrate

Com isso, todas as classes definidas no arquivo models.py serão transformadas em tabelas no banco de dados.

Executar Servidor de Desenvolvimento

Para executar o servidor de desenvolvimento do Django e, assim, testar nosso projeto, utilizamos o seguinte comando:

python manage.py runserver

Este comando irá executar o servidor do Django no endereço http://localhost:8000, que poderá ser utilizado para executar o projeto, como podemos ver na imagem abaixo:

Limpar Banco de Dados

Quando estamos desenvolvendo nossa aplicação, é comum que queiramos limpar todos os dados do banco de dados para realizar novos testes. Para realizar este procedimento, utilizamos o seguinte comando:

python manage.py flush

Este comando irá limpar todos os dados salvos no banco de dados do projeto, mantendo sua estrutura.

Abrir Shell do Banco de Dados Configurado

Se quisermos manipular o banco de dados diretamente do shell do SGBD, podemos utilizar o seguinte comando para criar uma conexão com o mesmo:

python manage.py dbshell

Este comando irá iniciar o shell do banco de dados ao qual o projeto django está configurado, como podemos ver abaixo:

Mapear BD existente para o projeto Django

Caso você possua um banco de dados já existente e queira mapeá-lo para seu projeto Django, o seguinte comando resolve esta necessidade:

python manage.py inspectdb > nome_da_app.models.py

Este comando irá mapear o banco de dados já existente no arquivo models.py da sua aplicação, conforme vimos neste artigo.

Utilizando o Redis como Cache em um projeto Django

A performance de um projeto é de vital importância para o sucesso de uma aplicação. Dificilmente um site que demore um tempo considerável para responder uma solicitação de um usuário, não sucumbirá ao fracasso. Pensando nisso, há diversas maneiras de tentar melhorar o desempenho de uma aplicação, dentre elas, utilizar o Cache para armazenar dados que são frequentemente utilizados, é uma ótima alternativa.

Como funciona o Cache

O Cache é um recurso que possibilita o acesso às informações de forma mais rápida. Basicamente, é uma forma de armazenar determinadas informações que são consumidas com mais frequência para que elas sejam disponibilizadas no menor tempo possível.

O funcionamento do Cache pode ser entendido da seguinte forma:

  1. A aplicação verifica se os dados solicitados estão em cache;

  2. Se sim, o cache devolve para a aplicação, que os exibe;

  3. Se não, os dados são obtidos do banco de dados, salvos no cache e retornados para aplicação;

  4. Da próxima vez, o cache já possuirá os dados armazenados e, assim, retornados em um tempo menor.

Instalando o Redis

A instalação do Redis varia conforme o sistema operacional utilizado, abaixo veremos como instalar o Redis no Windows, Linux e macOS.

Windows

A instalação do Redis no Windows é bem simples. Primeiro, precisamos baixar o arquivo .zip do diretório oficial do Redis ():

Após realizar o download, descompactamos e executamos o arquivo redis-server, localizado no diretório 32bits ou 64bits, dependendo do sistema operacional.

Linux

A instalação do Redis no Linux também é bem simples. Primeiro, abrimos o terminal e digitamos os seguintes comandos:

sudo apt-get install redis-server
sudo systemctl enable redis-server.service

Com isso, o Redis será instalado e executado no Linux.

macOS

Para instalar o Redis no macOS também é super simples. Com o Homebrew instalado, podemos abrir o terminal e digitar o seguinte comando:

brew install redis
ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents

Com isso, o Redis será instalado e configurado para iniciar sempre que ligarmos o computador.

Configurando o Redis no Django

Com o Redis instalado, precisamos configurar a comunicação entre as tecnologias (Django e Redis). Para isso, o primeiro passo é instalar o pacote django-redis na virtualenv do projeto seguindo os seguintes passos:

No PyCharm, vamos até a aba “Project Interpreter” e clicamos no “+” localizado no canto inferior esquerdo:

Após isso, buscamos pelo pacote “django-redis” e o instalamos em nossa virtualenv:


Com isso, o Redis já está pronto para ser utilizado em nosso projeto Django 🙂

Utilizando o Redis como Cache

Após instalar e configurar o Redis em nosso projeto Django, precisamos configurar o projeto para utilizar o Redis como Cache das informações. Para isso, no arquivo settings.py, adicionamos a seguinte configuração:

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient'
        },
        'KEY_PREFIX': 'django_orm'
    }
}

A configuração acima permitirá que o Django se comunique com o servidor do Redis que está sendo executado localmente.

Agora precisamos indicar quais páginas utilizarão o Cache para armazenar suas informações. Para isso, no nosso arquivo de views do projeto, adicionamos a anotação @cache_page(tempo_de_vida_cache) nos métodos que queremos utilizar o cache (normalmente, nas páginas com mais acessos):

@cache_page(60)
def listar_clientes(request):
    clientes = cliente_service.listar_clientes()
    return render(request, 'clientes/lista_clientes.html', {'clientes': clientes})

Com isso, sempre que um usuário solicitar o método para listagem de todos os clientes, o Django, primeiro, verificará se estas informações existem no Redis. Se sim, é de lá que as informações serão listadas, caso contrário, o Django fará uma consulta no banco de dados, obterá a lista de clientes, inserirá no cache e retornará ao usuário.

Comparando performances

A quantidade de requisições por segundo pode variar um pouco, mas é bem nítido o ganho de performance do uso do Redis como Cache em nossa aplicação. Na imagem abaixo podemos ver a diferença entre a quantidade de requisições utilizando o Redis e o uso do banco de dados:

Conclusão

O uso do Cache é uma ótima alternativa quando precisamos garantir o retorno dos dados em um tempo menor em páginas que são frequentemente acessadas. Vale lembrar que não devemos (e nem precisamos) usá-lo em todas as páginas, apenas nas mais acessadas.

Mapeando banco de dados existente com Django

O Django é um ótimo framework para iniciar um projeto completamente do zero, mas nem sempre este é nosso caso. Imagine que uma empresa pretende migrar uma aplicação legada (antiga) com 100 tabelas em seu banco de dados e escolhe o Django como sua nova tecnologia… Como faríamos para mapear todo o banco de dados (tabelas e relações) para nosso projeto? Parece algo cansativo e complicado, certo!? Bom, com o Django, isso pode ser mais fácil do que parece…

Banco de Dados

Para nosso exemplo, iremos utilizar um banco de dados com uma estrutura que armazena a lista de empregados de uma empresa e suas relações. Não vamos nos preocupar com a estrutura do banco de dados em si, o importante aqui é entender que teremos 6 tabelas com os seguintes campos:

Para criar o banco de dados acima em seu MySQL, precisamos baixar toda a sua estrutura no repositório encontrado no seguinte link:

Depois disso, vamos baixar seu código-fonte e salvar no Desktop do nosso computador. Depois de descompactado, utilizamos o terminal para incorporar o banco de dados teste para o MySQL presente em nossa máquina. Para isso, no terminal (ou CMD), utilizamos o seguinte comando:

mysql -u root -p < employees.sql

Lembrando que o “root” é o nome do usuário do banco de dados. Caso o seu seja diferente, informe-o na instrução acima 🙂

Depois disso, o banco employees será criado no MySQL:

Lembrando que o BD que utilizamos já virá populado, contendo mais de 300,000 empregados registrados. Situação parecida ao que descrevemos anteriormente:

Configurando aplicação

Após criar o banco de dados, estamos prontos para mapeá-lo em nosso projeto Django. Para isso, partiremos de uma aplicação “zerada”, apenas com o projeto e uma app criada. Além disso, precisamos instalar, obviamente, o Django e o mysqlclient em nossa virtualenv:


Além disso, precisamos configurar o projeto para se comunicar com o banco de dados que acabamos de importar. Para isso, no arquivo settings.py do nosso projeto, determinamos seus parâmetros de conexão:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'employees',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': 'localhost',
        'PORT': '3306'
    }
}

Com isso, temos nossa aplicação criada e se comunicando com o banco de dados \o

Mapeando o banco de dados no Django

Depois de configurar a aplicação, chegou a hora tão esperada: mapear o banco de dados para nosso arquivo models.py 😀

Para isso, é muito simples (e você vai se impressionar com isso). Tudo que temos que fazer é abrir o terminal integrado do PyCharm e digitar o seguinte comando:

python manage.py inspectdb > nome_da_app.models.py

Lembrando que “nome_da_app” deve ser alterada pelo nome da sua app no projeto, hein!? 🙂

Após isso, no arquivo models.py da nossa aplicação, teremos o seguinte resultado:

from django.db import models


class Departments(models.Model):
    dept_no = models.CharField(primary_key=True, max_length=4)
    dept_name = models.CharField(unique=True, max_length=40)

    class Meta:
        managed = False
        db_table = 'departments'


class DeptEmp(models.Model):
    emp_no = models.ForeignKey('Employees', models.DO_NOTHING, db_column='emp_no', primary_key=True)
    dept_no = models.ForeignKey(Departments, models.DO_NOTHING, db_column='dept_no')
    from_date = models.DateField()
    to_date = models.DateField()

    class Meta:
        managed = False
        db_table = 'dept_emp'
        unique_together = (('emp_no', 'dept_no'),)


class DeptManager(models.Model):
    emp_no = models.ForeignKey('Employees', models.DO_NOTHING, db_column='emp_no', primary_key=True)
    dept_no = models.ForeignKey(Departments, models.DO_NOTHING, db_column='dept_no')
    from_date = models.DateField()
    to_date = models.DateField()

    class Meta:
        managed = False
        db_table = 'dept_manager'
        unique_together = (('emp_no', 'dept_no'),)


class Employees(models.Model):
    emp_no = models.IntegerField(primary_key=True)
    birth_date = models.DateField()
    first_name = models.CharField(max_length=14)
    last_name = models.CharField(max_length=16)
    gender = models.CharField(max_length=1)
    hire_date = models.DateField()

    class Meta:
        managed = False
        db_table = 'employees'


class Salaries(models.Model):
    emp_no = models.ForeignKey(Employees, models.DO_NOTHING, db_column='emp_no', primary_key=True)
    salary = models.IntegerField()
    from_date = models.DateField()
    to_date = models.DateField()

    class Meta:
        managed = False
        db_table = 'salaries'
        unique_together = (('emp_no', 'from_date'),)


class Titles(models.Model):
    emp_no = models.ForeignKey(Employees, models.DO_NOTHING, db_column='emp_no', primary_key=True)
    title = models.CharField(max_length=50)
    from_date = models.DateField()
    to_date = models.DateField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'titles'
        unique_together = (('emp_no', 'title', 'from_date'),)

Exatamente a mesma estrutura (com seus atributos e relacionamentos) presentes no banco de dados que incorporamos ao MySQL da nossa máquina. Bem legal, né!?

Imagine ter que mapear todas essas entidades, avaliando seus tipos de dados e relações… Seria um trabalho bem cansativo, concorda? Com o Django, um simples comando consegue resolver este problema 🙂

Agora, já estamos prontos para utilizar todo o poder do ORM do Django para manipular o banco de dados e, consequentemente, criar nossa nova aplicação \o

Relacionamento 1-1, 1-N e N-N com Django

No modelo relacional, existem três tipos de associação entre entidades (tabelas) distintas. Estas relações são utilizadas para mapear como as tabelas interagem entre si e podem ser classificadas de três formas: 1-1 (um para um), 1-N (um para muitos) e N-N (muitos para muitos).

Sendo assim, veremos neste artigo como funciona e como implementar os três tipos de relacionamento no Django.

Django - Fundamentos
Curso de Django - Fundamentos
CONHEÇA O CURSO

Relacionamento 1-1

Assim como o próprio nome supõe, o relacionamento 1-1 define que um item de uma entidade só poderá se relacionar com um item de outra entidade. Por exemplo, supondo que temos as entidades Cliente e Endereço que se relacionam de forma 1-1, um cliente só poderá possuir um endereço, que também só pode estar relacionado a um cliente.

Para criar este tipo de relacionamento no Django, no arquivo models.py, precisamos criar um campo que armazene o ID do endereço na entidade cliente do tipo OneToOneField:

class Endereco(models.Model):
        # Definimos seus atributos

class Cliente(models.Model):
        # Definimos seus atributos
      endereco = models.OneToOneField(Endereco, on_delete=models.SET_NULL, null=True)

Desta forma, a classe Cliente irá armazenar o ID do Endereço que cada cliente possuirá. O código completo das classes Endereço e Cliente podem ser vistas abaixo:

class Endereco(models.Model):
    rua = models.CharField(max_length=200, null=False, blank=False)
    numero = models.IntegerField(null=False, blank=False)
    complemento = models.CharField(max_length=200, null=False, blank=False)
    bairro = models.CharField(max_length=50, null=False, blank=False)
    cidade = models.CharField(max_length=100, null=False, blank=False)
    pais = models.CharField(max_length=50, null=False, blank=False)

    def __str__(self):
        return self.rua

class Cliente(models.Model):
    SEXO_CHOICES = (
        ("F", "Feminino"),
        ("M", "Masculino"),
        ("N", "Nenhuma das opções")
    )

    nome = models.CharField(max_length=100, null=False, blank=False)
    data_nascimento = models.DateField(null=False, blank=False)
    email = models.EmailField(null=False, blank=False)
    profissao = models.CharField(max_length=50, null=False, blank=False)
    sexo = models.CharField(max_length=1, choices=SEXO_CHOICES, blank=False, null=False)
    endereco = models.OneToOneField(Endereco, on_delete=models.SET_NULL, null=True)

Após definir as classes acima, precisamos criar a migração para efetivar as alterações no banco de dados e, assim, criar as tabelas no banco de dados. Para isso, utilizamos os comandos abaixo:

python manage.py makemigrations

python manage.py migrate

Isso fará com que as tabelas sejam criadas no banco de dados com a seguinte estrutura:

Relacionamento 1N

O relacionamento 1N determina que um item de uma tabela pode se relacionar com vários itens de uma outra tabela. Continuando o exemplo acima, podemos determinar que um cliente pode realizar diversos pedidos em um restaurante, porém cada pedido só pode possuir um cliente atrelado a ele.

Para criar este relacionamento no Django, utilizamos um campo do tipo ForeignKey, como podemos ver abaixo:

class Pedido(models.Model):
    cliente = models.ForeignKey("Cliente", on_delete=models.CASCADE, related_name='pedidos')

Isso fará com que a tabela Pedidoarmazene o ID do cliente de cada relação. O código completo das classes Pedido e Cliente pode ser visto abaixo:

class Pedido(models.Model):
    STATUS_CHOICES = (
        ("P", "Pedido realizado"),
        ("F", "Fazendo"),
        ("E", "Saiu para entrega"),
    )
    cliente = models.ForeignKey("Cliente", on_delete=models.CASCADE, related_name='pedidos')
    observacoes = models.CharField(max_length=300, null=False, blank=False)
    data_pedido = models.DateTimeField(default=timezone.now)
    valor = models.FloatField(blank=False, null=False)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, blank=False, null=False)

    def __str__(self):
        return self.cliente.nome

class Cliente(models.Model):
    SEXO_CHOICES = (
        ("F", "Feminino"),
        ("M", "Masculino"),
        ("N", "Nenhuma das opções")
    )

    nome = models.CharField(max_length=100, null=False, blank=False)
    data_nascimento = models.DateField(null=False, blank=False)
    email = models.EmailField(null=False, blank=False)
    profissao = models.CharField(max_length=50, null=False, blank=False)
    sexo = models.CharField(max_length=1, choices=SEXO_CHOICES, blank=False, null=False)
    endereco = models.OneToOneField(Endereco, on_delete=models.SET_NULL, null=True)

Após definir as classes acima, precisamos criar a migração para efetivar as alterações no banco de dados e, assim, criar as tabelas no banco de dados. Para isso, utilizamos os comandos abaixo:

python manage.py makemigrations

python manage.py migrate

Isso fará com que as tabelas sejam criadas no banco de dados com a seguinte estrutura:

Agora, a tabela Pedido armazenará, além de todos os seus atributos, o ID do cliente. Assim, um cliente poderá estar relacionado a vários pedidos, porém um pedido só pode se relacionar com um único cliente.

Django - Fundamentos
Curso de Django - Fundamentos
CONHEÇA O CURSO

Relacionamento NN

O relacionamento NN define que um item de uma tabela pode se relacionar com vários itens de uma outra tabela e vice-versa. Por exemplo, podemos determinar que um pedido pode possuir diversos produtos relacionados a ele, assim como um mesmo produto pode estar relacionado a diversos pedidos diferentes.

Para criar este tipo de relacionamento, utilizamos um campo do tipo ManyToManyField, como podemos ver abaixo:

class Produto(models.Model):
    nome = models.CharField(max_length=50, null=False, blank=False)
    descricao = models.CharField(max_length=200, null=False, blank=False)
    valor = models.FloatField(null=False, blank=False)

    def __str__(self):
        return self.nome

class Pedido(models.Model):
    STATUS_CHOICES = (
        ("P", "Pedido realizado"),
        ("F", "Fazendo"),
        ("E", "Saiu para entrega"),
    )
    cliente = models.ForeignKey("Cliente", on_delete=models.CASCADE, related_name='pedidos')
    observacoes = models.CharField(max_length=300, null=False, blank=False)
    data_pedido = models.DateTimeField(default=timezone.now)
    valor = models.FloatField(blank=False, null=False)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, blank=False, null=False)
    produtos = models.ManyToManyField(Produto)

    def __str__(self):
        return self.cliente.nome

Após definir as classes acima, precisamos criar a migração para efetivar as alterações no banco de dados e, assim, criar as tabelas no banco de dados. Para isso, utilizamos os comandos abaixo:

python manage.py makemigrations

python manage.py migrate

Isso fará com que as tabelas sejam criadas no banco de dados com a seguinte estrutura:

Para este tipo de relacionamento, uma tabela “auxiliar” será criada para armazenar os IDs do pedido e do produto que se relaciona.

A tabela clientes_pedido_produtosirá armazenar o id do pedido e o id do produto que fazem relação. Desta forma, um pedido pode se relacionar com diferentes produtos e um produto pode estar relacionado a diferentes pedidos.

Conclusão

Vimos neste artigo o quão simples é criar os três tipos de relacionamento em bancos de dados relacionais utilizando o ORM do Django. Com isso, agora podemos criar nossas aplicações e estruturar nosso banco de dados da melhor forma possível.

O que é Django?

O Django é um framework gratuito e de código aberto escrito em Python para desenvolvimento web. Sua utilização permite a construção de aplicações web de alto desempenho.

Django - Fundamentos
Curso de Django - Fundamentos
CONHEÇA O CURSO

O que é um Framework?

O framework é um facilitador no desenvolvimento de diversas aplicações, e sem dúvida, sua utilização poupa tempo e custos para quem utiliza, pois de forma mais básica, é um conjunto de bibliotecas utilizadas para criar uma base onde as aplicações são construídas, um otimizador de recursos. Tem como principal objetivo resolver problemas recorrentes com uma abordagem mais genérica. Ele permite ao desenvolvedor focar nos “problemas” da aplicação, não na arquitetura e configurações.

História do Django

Lançado em 2005 sob a licença BSD (de código aberto), o Django foi desenvolvido inicialmente como um sistema de gerenciamento de um site jornalístico. Tem como seus co-criadores os desenvolvedores Adrian Holovaty e Simon Willison. A escolha do nome “Django” foi inspirado no músico de jazz Django Reinhardt, considerado um dos melhores e mais influentes guitarristas de todos os tempos. \o/

Padrão MTV

O Django utiliza o padrão de projeto MTV (Model, Template e View), que é basicamente:

Model: Onde acontece toda interação com o banco de dados;

Template: Onde acontece a renderização dos dados para uma visualização mais intuitiva, em outras palavras, a interação do usuário com o site em Django;

E a View: Lógica sobre os dados. A camada responsável pelas regras de negócio do sistema Django.

Por ser popular, o Django possui uma grande comunidade de desenvolvedores. Com isso, fica muito mais fácil encontrar materiais de estudo e programadores dispostos a se ajudarem.

Utiliza o princípio Don´t Repeat Yourself ou simplesmente DRY, permitindo que as aplicações sejam desenvolvidas com a maior quantidade de aproveitamento de código possível.

Concluindo:

Com isso, vimos algumas das principais características do Django, o que o torna um framework muito utilizado e que, com certeza, você deve levar em consideração quando iniciar um projeto. =)

Utilizando arquivos estáticos em um projeto Django

A utilização de arquivos estáticos no Django necessita de algumas configurações para ser feita, como veremos neste artigo 🙂

Django - Fundamentos
Curso de Django - Fundamentos
CONHEÇA O CURSO

Configurando aplicação

Com a aplicação aberta no PyCharm, precisamos configurar o diretório em que os arquivos estáticos (JS, CSS e IMG) serão armazenados. Para isso, vamos até o final do arquivo settings.py do nosso projeto até encontrar a configuração STATIC_URL, é ela quem define o diretório que os arquivos estáticos serão armazenados.

Por padrão, o Django armazena os arquivos estáticos em um diretório chamado static, localizado na aplicação. Sendo assim, é lá que vamos armazenar os arquivos CSS, JS e IMG da aplicação.

Para isso, o primeiro passo é criar um diretório chamado static na aplicação e, dentro do diretório static, criar uma outra pasta com o nome da aplicação. Por exemplo, se a aplicação possuir o nome “minha_aplicacao”, precisamos criar um diretório static/minha_aplicacao dentro da app que estamos desenvolvendo:

Note que na imagem acima, estamos criando um diretório com o mesmo nome da aplicação “app” dentro do diretório “static” e, dentro do diretório “app”, criamos as pastas para armazenar os arquivos css, js e img.

Com isso, só precisamos armazenar os arquivos estáticos do projeto em seu respectivo diretório. Como exemplo, vamos criar um arquivo css simples e armazená-lo no diretório static/app/css com o nome style.css e com o seguinte conteúdo:

body {
  background-color: lightblue;
}

h1 {
  color: navy;
  margin-left: 30px;
}
Django - Templates
Curso de Django - Templates
CONHEÇA O CURSO

Utilizando arquivos nos templates

Agora que já configuramos a localização dos arquivos estáticos e criamos o css de exemplo, precisamos importá-lo em nossos templates. Para isso, o processo é bem simples:

1 – Carregamos a tag static do Django em nosso template (linha 2);

2 – Carregamos o arquivo css utilizando a tag (linha 7). Note que precisamos determinar o caminho, a partir do diretório static, do arquivo css que criamos anteriormente.

<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Página de testes</title>
    <link rel="stylesheet" href="{% static 'app/css/style.css' %}">
</head>
<body>

<h1>Olá, mundo</h1>

</body>
</html>

Testando aplicação

Agora, ao executar a aplicação e renderizar o template com o css importado, teremos o seguinte resultado:

Deploy de uma aplicação Django no Heroku

Hoje, a principal forma de entrega e uso de uma aplicação é por meio da nuvem. É por lá que as aplicações são armazenadas e acessadas. Sendo assim, é imprescindível que uma aplicação seja armazenada em algum servidor e disponível pela internet.

Pensando nisso, veremos neste artigo como realizar o Deploy de uma aplicação Django e disponibilizá-la no Heroku, serviço de armazenamento em nuvem de aplicações.

Clonando o repositório da aplicação

Como exemplo, iremos utilizar a aplicação feita no curso “Django – Fundamentos” aqui da TreinaWeb. Apesar de ser uma aplicação simples, será um ótimo exemplo para testes.

Django - Fundamentos
Curso de Django - Fundamentos
CONHEÇA O CURSO

Para realizar o clone do projeto, vamos até o CMD (se você usa o Windows) ou Terminal (caso você use o macOS ou Linux) e utilizamos o seguinte comando:

git clone https://github.com/treinaweb/treinaweb-django-fundamentos.git

Feito isso, o projeto será baixado em seu computador e você terá todo o seu código-fonte.

Criar conta no Heroku

Após baixar o código-fonte do projeto, precisamos criar uma conta (ou realizar o login) no Heroku. O processo é bem simples, basta preencher o formulário na página de cadastro do site (https://signup.heroku.com/):

Caso você já possua uma conta no Heroku, só será necessário realizar o login (https://id.heroku.com/login).

Depois disso, você será redirecionado para a página inicial do Heroku:

Criar app no Heroku

Depois de criar uma conta no Heroku, precisamos criar uma app para armazenar a aplicação Django. Para isso, na página inicial, clicamos no botão “Create New App”. Depois, na próxima página, definimos o nome da aplicação que estamos criando e clicamos no botão “Create App”:

Com isso, seremos redirecionados para a página de configuração da aplicação. É nela que configuramos o servidor em que a aplicação será armazenado.

Instalar o Heroku CLI

Para que seja possível enviar o código-fonte do projeto para o servidor que acabamos de criar, precisamos instalar o CLI (Command Line Interface) do Heroku. É com ele que conseguimos executar determinados comandos utilizando nosso computador para gerenciar o servidor da aplicação.

Para isso, há uma página que contém todas as informações necessárias para esse processo. Lembrando que o Heroku CLI é multi-plataforma, ou seja, poderá ser utilizado em qualquer SO (Windows, macOS ou Linux).

Todo o processo de instalação está descrito na documentação do Heroku (https://devcenter.heroku.com/articles/heroku-cli) e é bastante simples.

Se você utiliza o macOS, você precisa digitar o seguinte comando em seu terminal:

brew tap heroku/brew && brew install heroku

Caso você utilize o Linux, o comando é o seguinte:

sudo snap install --classic heroku

Agora, caso você utilize o Windows, você precisará baixar e executar o instalador do Heroku CLI, também disponível na página citada acima:

Lembrando que, para qualquer SO, é necessário possuir o Git instalado. Mas, já que você fez o clone do repositório do projeto, isso já deve estar funcionando 🙂

Logar no Heroku CLI

Depois de baixar e instalar o Heroku CLI, precisamos logar com nossa conta na ferramenta. Para isso, vamos até o CMD (ou Terminal) e digitamos o seguinte comando:

heroku login

Uma mensagem no terminal será exibida e podemos clicar em qualquer tecla do teclado. Neste momento, o navegador irá abrir uma página para realizarmos o login no Heroku. Após digitarmos nossos dados de acesso, clicamos no botão “Login” e o processo será encerrado com sucesso:

Configurar Projeto

Com todas as configurações do Heroku prontas, chegou a hora de configurarmos a aplicação que será armazenada no servidor. Para isso, o primeiro passo é instalar a biblioteca django-heroku, responsável por automatizar as configurações do nosso projeto com o Heroku.

Instalar o django-heroku

Para instalar o django-heroku, vamos até a janela de configuração da nossa virtualenv do PyCharm (Arquivo > Settings > Project Interpreter, caso você utilize o Windows ou Linux ou PyCharm Community Edition > Preferences > Project Interpreter, caso você utilize o macOS), clicamos no botão “+” no canto inferior esquerdo e buscamos a biblioteca pelo seu nome, como podemos ver abaixo:

Depois disso, a biblioteca será instalada em nossa virtualenv e estaremos prontos para configurá-la em nosso projeto. Sendo assim, vamos até o arquivo settings.py e ativamos o django-heroku adicionando o seguinte conteúdo no final do arquivo :

# Configure Django App for Heroku.
import django_heroku
django_heroku.settings(locals())

Feito isso, as configurações do Heroku em nossa aplicação estão prontas.

Criar Procfile

Depois de instalar o django-heroku, precisamos criar o arquivo Procfile na raiz do nosso projeto. É ele quem vai definir qual arquivo será usado para processar as requisições da nossa aplicação. No Django, esse arquivo é o wsgi.py, localizado na pasta da nossa aplicação.

Sendo assim, criamos um arquivo de texto simples com o nome Procfilee salvamos na raiz do nosso projeto. Dentro dele, colamos o seguinte conteúdo:

web: gunicorn tw_clientes.wsgi

Lembrando que o nome da sua aplicação pode variar, caso você não esteja utilizando o mesmo projeto citado anteriormente. Se este for o seu caso, altere o “tw_cliente.wsgi” para o nome da sua aplicação.

Depois disso, precisamos instalar a biblioteca gunicorn, servidor HTTP para aplicações Python. O processo é o mesmo que o django-heroku, porém devemos pesquisar por gunicornna janela de instalação de bibliotecas:

Criar requirements.py

Depois disso, precisamos criar o arquivo requirements.py para armazenar as bibliotecas utilizadas no projeto. Lembrando que você precisa estar com a virtualenv ativa no PyCharm.

Sendo assim, o comando para gerar o arquivo requirements.pycom base nas bibliotecas instaladas na virtualenv do projeto é o seguinte:

pip freeze > requirements.txt

Com isso, o arquivo requirements.txtserá criado na raiz do projeto com o seguinte conteúdo:

dj-database-url==0.5.0
Django==2.1.7
django-heroku==0.3.1
gunicorn==19.9.0
mysqlclient==1.4.2
psycopg2==2.7.7
pytz==2018.9
whitenoise==4.1.2

São essas as bibliotecas utilizadas em nosso projeto. Lembrando que o conteúdo deste arquivo pode variar caso você tenha mais bibliotecas em sua virtualenv.

Lembrando que a lista de bibliotecas utilizadas pode ser vista na janela de configurações do PyCharm (Arquivo > Settings > Project Interpreter, caso você utilize o Windows ou Linux ou PyCharm Community Edition > Preferences > Project Interpreter, caso você utilize o macOS):

Realizar o Deploy

Finalmente, após todas as configurações, estamos prontos para subir nosso projeto no Heroku o/.

Subindo aplicação

Para isso, vamos até o terminal e digitamos o seguinte comando:

heroku git:remote -a django-treinaweb
git add .
git commit -m "Deploy da aplicação"
git push -u heroku master

Depois disso, uma mensagem será exibida no terminal indicando que o deploy foi feito com sucesso:

Clicando no link indicado, somos redirecionados para a página da aplicação que acabou de ser armazenada. Neste momento, a página que será exibida terá o seguinte visual:

Como sabemos, essa é a página de erro do Django. Sendo assim, ao que tudo indica, o Deploy foi feito com sucesso. Sendo assim, se navegarmos até a página https://django-treinaweb.herokuapp.com/clientes/listar teremos o seguinte:

O erro acima indica que o Django não conseguiu encontrar as tabelas que estamos utilizando no banco de dados. E isso faz sentido, já que, até o momento, não migramos o conteúdo dos arquivos de migração para o Heroku. Sendo assim, este é o último passo a ser realizado.

Criando banco de dados

Para executar o comando responsável por criar o banco de dados no heroku, vamos até o terminal e digitamos o seguinte comando:

heroku run python manage.py migrate

O comando acima irá executar as migrações no banco de dados do Heroku e criar toda a sua estrutura:

Agora, ao retornar para a página anterior, podemos ver que a aplicação está sendo executada sem qualquer erro:

Inclusive, podemos utilizar qualquer recurso da nossa aplicação, como o cadastro de novos clientes:


Agora, toda a nossa aplicação já está disponível e funcional diretamente da nuvem através do Heroku 🙂