Django Tutorial
Django Tutorial
Django Tutorial
AZEVEDO
PYTHON E
DJANGO
FRAMEWORK
Raíssa Azevedo
PARA
Beginners BR
APRESENTADO POR
Raíssa Azevedo
APRESENTAÇÃO
Neste pequeno ebook você vai encontrar todos os passos básicos para
desenvolver um sistema web utilizando Django Framework.
Raíssa Azevedo
COMANDOS IMPORTANTES
• Instalar o django
pip install django ou pip3 install django
• Arquitetura Cliente-Servidor
É um modelo de computação distribuída em que um sistema é dividido
em duas partes principais: o cliente, que é responsável pela
interação com o usuário e a interface gráfica, e o servidor, que
é responsável pelo processamento dos dados e pela lógica de
negócios.
• Protocolo HTTP
HTTP (Hypertext Transfer Protocol) é um protocolo de comunicação
usado para transferir dados pela internet. Ele define como os
dados serão formatados e transmitidos entre clientes e servidores
web.
Os verbos HTTP são métodos que definem a ação a ser realizada em
um determinado recurso. Os principais verbos HTTP são:
GET: solicita um recurso ao servidor;
POST: envia dados ao servidor para serem processados;
PUT: atualiza um recurso existente no servidor;
DELETE: remove um recurso do servidor;
HEAD: solicita apenas informações sobre o recurso, sem obtê-lo;
OPTIONS: obtém informações sobre os métodos HTTP suportados pelo
servidor.
Existem outros verbos HTTP menos comuns, como PATCH, TRACE,
CONNECT, entre outros.
Outros conceitos:
Chave estrangeira – Também conhecido como foreign key ou fk. É um
atributo presente em uma entidade que indica um relacionamento e
representa a chave primária de uma entidade
Grau de relacionamento – Indica a quantidade de entidades ligadas a um relacionamento. Pode ser: Unário, binário ou
Ternário.
Unário – Grau 1, é quando uma entidade se relaciona com ela mesmo.
Binário – Grau 2, onde uma entidade se relaciona com outra entidade, é o tipo mais comum de relacionamento.
Ex:
Ternário – Grau 3, onde três entidades estão relacionadas por um mesmo relacionamento.
Após fazer as aplicações básicas no settings do projeto do django. Seguir para o models presente no app core.
class Chassi(models.Model):
numero = models.CharField('Chassi', max_length=16, help_text='Máximo:16 caracteres')
class Meta:
verbose_name = "Chassi"
verbose_name_plural = 'Chassis'
def __str__(self):
return self.numero
O modelo Chassi implica em cadastrar o Chassi de veículos, que é a estrutura de identificação do veiculo. O Chassi é
único.
class Carro(models.Model):
chassi = models.OneToOneField(Chassi, on_delete=models.CASCADE)
modelo = models.CharField('Modelo', max_length=30, help_text='Máximo:30 caracteres')
preco = models.DecimalField('Preço', max_digits=8, decimal_places=2)
descricao = models.TextField('Descrição', max_length=500, help_text='Máximo:500 caracteres')
class Meta:
verbose_name = 'Carro'
verbose_name_plural = 'Carros'
def __str__(self):
return self.modelo
O relacionamento One to One significa que: Cada carro só pode relacionamento com 1 Chassi. Ou seja, um mesmo
chassi também não pode estar relacionado a dois carros. Ou seja, um carro, um chassi (One2One).
No admin.py:
@admin.register(Chassi)
class ChassiAdmin(admin.ModelAdmin):
list_display = ['numero']
@admin.register(Carro)
class CarroAdmin(admin.ModelAdmin):
list_display = ['’modelo’, ‘chassi’, ‘descricao’, ‘preco’]
Obs: Toda vez que criar um modelo executar as migrations.
Em seguida executar os comandos para a criação de super usuário para administração do Banco de dados relacional:
Como não há um template criado ainda. Ficará somente a base administrativa padrão do Django:
>>> print(carros.query)
SELECT "core_carro"."id", "core_carro"."chassi_id", "core_carro"."modelo", "core_carro"."preco",
"core_carro"."descricao" FROM "core_carro"
>>>
É possível recuperar toda e qualquer informação fornecida através da primary key (pk) do carro através do Sheel.
>>> carro
<Carro: Corolla Cross XR 2.0>
>>> carro.modelo
'Corolla Cross XR 2.0'
>>> carro.preco
Decimal('139990.00')
>>> carro.descricao
'Sete airbags, câmera de ré com projeção na central multimídia (só as versões XRE, XRV e XRX têm guias
dinâmicas), controle de estabilidade, controle de tração, assistente de partida em rampa, sensor de estacionamento
traseiro, faróis com acendimento automático e ajuste de altura elétrico, faróis de neblina dianteiros em LED,.'
>>> carro.chassi
<Chassi: 111sjdnsadn22535>
Mesmo a classe Chassi sendo construída separada da classe carro nos Models… Ela pôde ser acessada sem fazer o
import no Shell devido ao relacionamento 1 para 1.
Chegando ao carro no Shell através do Chassi:
Devido ao relacionamento One 2 One é possível acessar os dados tendo o número do Chassi fornecido na classe Chassi.
Ou tendo a chave primária do carro fornecido em outra classe nos models.
class Montadora(models.Model):
nome = models.CharField('Nome', max_length=50)
class Meta:
verbose_name = "Nome"
verbose_name_plural = 'Nomes'
def __str__(self):
return self.nome
class Carro(models.Model):
chassi = models.OneToOneField(Chassi, on_delete=models.CASCADE)
modelo = models.CharField('Modelo', max_length=30, help_text='Máximo:30 caracteres')
preco = models.DecimalField('Preço', max_digits=8, decimal_places=2)
descricao = models.TextField('Descrição', max_length=500, help_text='Máximo:500 caracteres')
montadora = models.ForeignKey(Montadora, on_delete=models.CASCADE)
class Meta:
verbose_name = 'Carro'
verbose_name_plural = 'Carros'
def __str__(self):
return f'{self.montadora} {self.modelo}'
Isso é feito dessa foram (Foreign Key). Porque cada carro possui apenas uma montadora. Mas uma montadora pode
produzir diversos carros. Por isso ela deve ser apenas uma chave estrangeira dentro da classe de veículos.
No Shell:
>>> from core.models import Carro
>>> carros = Carro.objects.all()
>>> carros
<QuerySet [<Carro: Toyota Corolla EX 2.0>, <Carro: Honda Fit>]>
class Carro(models.Model):
chassi = models.OneToOneField(Chassi, on_delete=models.CASCADE)
modelo = models.CharField('Modelo', max_length=30, help_text='Máximo:30 caracteres')
preco = models.DecimalField('Preço', max_digits=8, decimal_places=2)
descricao = models.TextField('Descrição', max_length=500, help_text='Máximo:500 caracteres')
montadora = models.ForeignKey(Montadora, on_delete=models.CASCADE)
motoristas = models.ManyToManyField(get_user_model())
Os usuários serão registrados na aba usuários da administração do Django:
E a seleção para motoristas de cada carro fica dentro das especificações de cada carro:
Assim é feito o controle de motoristas, os motoristas autorizado ficam com a coloração acinzentada no menu de
descrição de cada veículo.
No Shell:
>>> from core.models import Carro
>>> carros = Carro.objects.all()
>>> carros
<QuerySet [<Carro: Toyota Corolla EX 2.0>, <Carro: Honda Fit>]>
>>> carro1 = carros.first()
>>> carro1
<Carro: Toyota Corolla EX 2.0>
>>> motors = carro1.motoristas.all()
>>> motors
<QuerySet [<User: raissa>, <User: Emilia>]>
Qual é, e quem são os motoristas do carro 2?
>>> carro2 = carros.last()
>>> carro2
<Carro: Honda Fit>
>>> motors2 = carro2.motoristas.all()
>>> motors2
<QuerySet [<User: Pedro>, <User: Emilia>]>
Isso é o relacionamento many to many, onde é possível ter vários carros com vários motoristas.
A medida que a complexidade de cada modelo relacional vai aumentando. Aumenta também a complexidade do query
desse modelo.
>>> print(motors2.query)
SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser",
"auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email",
"auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" INNER JOIN
"core_carro_motoristas" ON ("auth_user"."id" = "core_carro_motoristas"."user_id") WHERE
"core_carro_motoristas"."carro_id" = 2
E se quiser saber a lista de carros que uma determinada lista de usuários dirige?
>>> motors
<QuerySet [<User: raissa>, <User: Emilia>]>
>>> m1 = motors.first()
>>> m1
<User: raissa>
>>> carros = Carro.objects.filter(motoristas=m1)
>>> carros
<QuerySet [<Carro: Toyota Corolla EX 2.0>]>
>>> print(carros.query)
SELECT "core_carro"."id", "core_carro"."chassi_id", "core_carro"."modelo", "core_carro"."preco",
"core_carro"."descricao", "core_carro"."montadora_id" FROM "core_carro" INNER JOIN "core_carro_motoristas"
ON ("core_carro"."id" = "core_carro_motoristas"."carro_id") WHERE "core_carro_motoristas"."user_id" = 1
Há uma repetição no nome dos carros, porque as vezes vários motoristas dirigem um mesmo carro.
Para filtrar:
>>> carros = Carro.objects.filter(motoristas__in = motors).distinct()
>>> carros
<QuerySet [<Carro: Toyota Corolla EX 2.0>, <Carro: Honda Fit>]>
>>>
Pronto agora o Shell exibe a lista sem repetição por causa do comando distinct() no final do comando de exibição dos
carros dirigidos pela lista 1 de motoristas.
Aproveitando os recurso do Django models:
O que acontece com o Banco de Dados se deletar uma montadora?
Ou seja, o Django pede pela confirmação de deleção, e indica o que será perdido ao deletar uma das montadoras salvas
no sistema. Que consiste em: 1 montadora, 1 carros e 2 relacionamentos de usuários que estão autorizados a dirigir.
Ou seja há uma remoção em cascata.
Ao indicar a montadora no models.py. Colocamos a função on_delete = models.CASCADE. Isso orienta o django a
fazer a remoção em cascada em tudo que tiver associado a montadora.
O on_delete em CASCADE deve ser adicionado tanto em Foreign Key quanto em many to many porque, se algo está
vinculado a um objeto e esse objeto(montadora) deixa de existir, todo o vinculo também precisa ser removido.
Porque o carro depende da foreign key e da montadora como seus vínculos de identificação.
Ou seja, se você deleta o Chassi, o carro também precisa de deixar de existir dentro do sistema.
A IMPORTÂNCIA DE REALIZAR TESTES AUTOMATIZADOS
Raíssa Azevedo
Após mais um dia desvendando as funcionalidades do Django Framework me deparei com o arquivo
tests.py. Estudando e me aprofundando a respeito cheguei aos seguintes passos de aprendizado:
Eu tinha um projeto de back-end realizado e publicado chamado Fusion. Já tinha dado o projeto como
finalizado. Mas, em todo o processo de criação, todos os testes que fiz buscando erros no código ou de lógica
de programação foram manuais. Ou seja, eu precisava simular um servidor, adicionar os dados, e verificar o
que me impedia de publicar.
Então, segue passos de realização de testes automatizados no modo de produção do Django Framework:
No arquivo __init__.py:
Foi realizado um teste do teste, que não está relacionado ao projeto, é somente para verificar se não há falha
no Framework (99% de certeza que não haverá):
# Teste de números
def add_num(num):
return num + 1
class SimplesTestCase(TestCase):
O teste unitário só irá retornar um valor True que indica que o teste automatizado está funcionando.
INICIANDO OS TESTES REAIS DO PROJETO
Na raiz do Projeto crie um arquivo .coveragerc
Esse arquivo irá indicar onde irá ocorrer os testes dentro do sistema criado
DENTRO DO ARQUIVO .COVERAGERC
[run]
source = .
Este “.” no código irá indicar que os testes irão ocorrer somente nas partes indicadas dentro do Projeto.
[run]
source = .
omit =
*/__init__.py
*/settings.py
*/manage.py
*/wsgi.py
*/apps.py
*/urls.py
*/admin.py
*/migrations/*
*/tests/*
*/asgi.py
Todos esses arquivos e diretórios já são testados pelo Django, portanto não há necessidade de fazer um novo
teste.
Seguido de:
coverage html
Isso irá gerar um diretório chamado Htmlcov
Através do terminal abra esse diretório e execute o seguinte código:
python3 -m http.server
Isso irá gerar um servidor de relatório de testes que irá indicar tudo que precisa ser testado no seu models.
O servidor irá parecer mais ou menos como esse:
E irá indicar o que precisa ser testado, o que falta ser testado e a porcentagem de cobertura de testes. Tudo
descrito em “Module” é um link que você pode abrir para encontrar mais dados específicos, como aqui no
models.py:
Se houver algo que precisa ser testado, irá estar com coloração vermelha. E o que está verde, é tudo que está
testado e sem presença de falhas. Esse relatório serve para indicar ao cliente a que pé anda seu projeto
também.
COMO SABER SE HÁ ERROS NA EXECUÇÃO DE UM TESTE DE USABILIDADE
Ao executar um comando de testes, e se não houver falhas, o sistema irá te retornar uma resposta como esta:
O sistema irá indicar a quantidade de falhas encontradas, qual arquivo está a falha e a linha exata onde está o
erro.
Obs: Toda vez que for executar um novo comando de teste, lembre-se primeiro de apagar o diretório
htmlcov/ com o seguinte código:
rm -rf htmlcov
Como citado anteriormente no texto, ao criar um projeto, você pode optar por testes manuais, mas só irá
descobrir onde estão as falhas de programação no momento de inserir os dados e executar. O que torna o
processo mais demorado. Uma vez o teste e executado, e indicando a presença de zero falhas, você poderá
seguir para a próxima etapa do processo com a consciência tranquila de não haver erro no seu código. Além
disso, um projeto com o comprovante de cobertura de testes 100% é um ponto positivo na carreira de
qualquer programador.
Raíssa Azevedo
Como o Django se comporta em aplicações em Tempo Real ?
Entendendo as aplicações Realtime:
Uma aplicação realtime é a que há o compartilhamento de dados de uma ponta a outra a distância, e o conceito é: “O
dado sai de um ponto estará disponível no outro ponto, no menor tempo possível”.
O PROJETO “realtime”:
Esse projeto vai contar com o banco de dados Redis.
urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('chat/<str:nome_sala>/', SalaView.as_view(), name='sala'),
]
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<nome_sala>\w+)/$', ChatConsumer.as_asgi()),
]
urlpatterns = [
path('', include('chat.urls')),
path('admin/', admin.site.urls),
]
Criar um arquivo routing.py dentro da do diretório do Preojeto realtime:
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
websocket_urlpatterns
)
),
})
class IndexView(TemplateView):
template_name = 'index.html'
class SalaView(TemplateView):
template_name = 'sala.html'
mark_safe – Do pacote SafeString é um função pra remover qualquer dado inseguro fornecido pelo usuário do chat.
Definindo os Templates:
No Index.html:
{% load bootstrap4 %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.ico">
<title>Rai Chat</title>
{% bootstrap_css %}
</head>
<body>
<div clas="container">
Qual sala de chat você gostaria de entrar?<br/>
<input id="nome_sala" name="nome_sala" type="text" size="100" placeholder="Nome da sala..."><br/>
{% buttons %}
<input id="botao" class="btn btn-primary" type="button" value="Entrar" />
{% endbuttons %}
</div>
<script>
document.querySelector('#nome_sala').focus();
document.querySelector('#nome_sala').onkeyup = function(e){
if(e.keyCode === 13){
document.querySelector('#botao').click();
}
};
document.querySelector('#botao').onclick = function(e){
var nome_sala = document.querySelector('#nome_sala').value;
if(nome_sala != ""){
window.location.pathname = '/chat/' + nome_sala + '/';
}else{
alert('Você precisa informar o nome da sala.');
document.querySelector('#nome_sala').focus();
}
};
</script>
{% bootstrap_javascript jquery='full' %}
</body>
</html>
No sala.html:
{% load bootstrap4 %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.ico">
<title>Rai Chat</title>
{% bootstrap_css %}
</head>
<body>
<div class="container">
<textarea id="sala" cols="70" rows="15"></textarea><br/>
<input id="texto" type="text" size="50"/><br/>
{% buttons %}
<input id="botao" type="button" value="Enviar" />
{% endbuttons %}
</div>
{% bootstrap_javascript jquery='full' %}
<script>
var nome_sala = {{ nome_sala_json }};
chatSocket.onmessage = function(e){
var dados = JSON.parse(e.data);
var mensagem = dados['mensagem'];
document.querySelector('#sala').value += (mensagem + '\n');
};
chatSocket.onclose = function(e){
console.error('O chat encerrou de forma inesperada.');
};
document.querySelector('#texto').focus();
document.querySelector('#texto').onkeyup = function(e){
if(e.keyCode === 13){
document.querySelector('#botao').click();
}
};
document.querySelector('#botao').onclick = function(e){
var mensagemInput = document.querySelector('#texto');
var mensagem = mensagemInput.value;
chatSocket.send(JSON.stringify({
'mensagem': mensagem
}));
mensagemInput.value = '';
};
</script>
</body>
</html>
Criando o Consumer:
O elo de ligação entre a aplicação no navegador e o projeto realtime:
class ChatConsumer(AsyncWebsocketConsumer):
# Entrar na sala
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
Quando trabalhamos com programação async é importante avisar que é assíncrona. Ela sendo assíncrona, todas as
funções e comandos executados que dependem de algum retorno/finalização. É utilizado o await.
Rodando a aplicação em tempo real:
Iniciando o servidor Redis:
Vai até onde o servidor Redis está salvo dentro os diretórios:
redis-cli
Executar os seguintes passos para verificar se não houve nenhum erro na instalação da biblioteca.
Criar um arquivo de rotas na aplicação core:
from django.urls import path
from .views import IndexView
urlpatterns = [
path('', IndexView.as_view(), name='index'),
]
Avisar a rotas do projeto:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('core.urls')),
path('admin/', admin.site.urls),
]
Criando os comandos para a geração do PDF:
Na views.py:
import io
from django.http import FileResponse
from django.views.generic import View
class IndexView(View):
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Report - Django</title>
<style>
body {
background: #0080ff;
}
</style>
</head>
<body>
<h1>Report - Django</h1>
{% for p in texto %}
<p>{{ p }}</p>
{% endfor %}
</body>
</html>
Na views.py:
class Index2View(View):
def get(self, request, *args, **kwargs):
texto = ['Geek University', 'Evolua seu lado Geek', 'Programação Web com Python e Django']
html = HTML(string=html_string)
html.write_pdf(target='/tmp/relatorio2.pdf')
fs = FileSystemStorage('/tmp')
Na urls da aplicação:
urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('2/', Index2View.as_view(), name='index2'),
]
Essas são as duas melhores formas de gerar arquivo PDF com Django.
Raíssa Azevedo
urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('dados/', DadosJSONView.as_view(), name='dados'),
]
urlpatterns = [
path('', include('core.urls')),
path('admin/', admin.site.urls),
]
Será necessária a criação dos templates:
{% load static %}
{% load bootstrap4 %}
<!doctype html>
<html lang="pt-br">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Charts!</title>
</head>
<body>
<div class="container">
<h1 class="text-primary">Charts!</h1>
</div>
<div class="container">
<canvas id="grafico" width="500" height="400"></canvas>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
{% bootstrap_javascript jquery='full' %}
<script type="text/javascript" src="{% static 'js/Chart.min.js' %}"></script>
<script type="text/javascript">
$.get('{% url 'dados' %}', function(data){
var ctx = $("#grafico").get(0).getContext("2d");
new Chart(ctx,{
type: 'line', data: data
});
});
</script>
</body>
</html>
Obs: Nesse projeto não se faz necessário a criação da pasta Static com os arquivos min.js, porque o Django entende que
é pra buscar dentro da biblioteca Static indicada no inicio da página HTML.
No Views.py:
from random import randint
from django.views.generic import TemplateView
from chartjs.views.lines import BaseLineChartView
class IndexView(TemplateView):
template_name = 'index.html'
class DadosJSONView(BaseLineChartView):
def get_label(self):
'''Retorna 12 labels para a apresentação do x'''
labels = [
'Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro'
]
return labels
def get_providers(self):
'''Retorna os nomes dos datassets'''
datasets = [
'Programação para Leigos',
'Algoritmos e Lógica de Programaçãp',
'Programação em C#',
'Programação em Python',
'Banco de Dados'
]
return datasets
def get_data(self):
'''Retorna 6 datasets para plotar o Gráfico
E cada linha representa um dataset,
Cada coluna representa um label
A quantidade de dados precisa ser igual aos datasets/labels'''
dados = []
for l in range(6):
for c in range(12):
dado = [
randint(1, 200), # Jan
randint(1, 200), # Fev
randint(1, 200), # Mar
randint(1, 200), # Abr
randint(1, 200), # Mai
randint(1, 200), # Jun
randint(1, 200), # Jul
randint(1, 200), # Ago
randint(1, 200), # Set
randint(1, 200), # Out
randint(1, 200), # Nov
randint(1, 200) # Dez
]
dados.append(dado)
return dados
O Randint irá gerar dados aleatórios de preenchimento para o gráfico. Gerando um número inteiro de 1 a 199.
Em seguida, executar o migrate:
python3 manage.py migrate
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
Depois, definir as rotas pra quando houver Login e o Logout da página.
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'index'
LOGOUT_URL = 'logout'
LOGOUT_REDIRECT_URL = 'login'
Em seguida, elaborar as rotas nas URLS. Na url do projeto, a configuração é padrão.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('core.urls')),
path('admin/', admin.site.urls),
]
urlpatterns = [
path('login/', LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('social-auth/', include('social_django.urls', namespace='social')),
path('', IndexView.as_view(), name='index'),
]
Isso ocorre devido as configurações de backend para a conexão de login com redes sociais não serem padrões do
django, entretanto, o framework possui algumas configurações facilitadoras.
Na views.py:
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
class LoginView(TemplateView):
template_name = 'login.html'
Os Templates:
A base.html:
{% load static %}
{% load bootstrap4 %}
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device.width, initial-scale=1.0"/>
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
{% bootstrap_css %}
<link rel="stylesheet" href="{% static 'css/style.css' %}"/>
<title>Django Social</title>
</head>
<body>
<div class="container-fluid">
<div>
<h1 class="text-white text-center">{% block title %}{% endblock %}</h1>
<div class="card p-5">
{% block content %}{% endblock %}
</div>
</div>
</div>
{% bootstrap_javascript jquery='full' %}
</body>
</html>
O index:
{% extends 'base.html' %}
{% load static %}
{% block title %}Inicio{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12 mb-3">
<h4 class="text-center">Bem vindo(a) {{ user.username }}</h4>
</div>
</div>
{% endblock %}
O login.html:
{% extends 'base.html' %}
{% load static %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-8 mx-auto social-container my-2 order-md-1">
<button class="btn btn-primary mb-2">
<a href="#">Login com Facebook</a>
</button>
</div>
</div>
{% endblock %}
Isso irá gerar uma página de login padrão:
Nas configurações básicas do aplicativo do facebook, denominar os dominios (localhost, ou onde o site tiver
hospedado).
Se a pessoa já tiver feito acesso pelo facebook, deslogado, e em outro dia logar novamente, a conta já está salva, e isso
impede a criação de uma exceção.
Qualquer seja a configuração para a criação de login através da rede social. Irá gerar essas duas chaves (Secret - Key).
Em seguida voltar ao facebook developers.
Copiar o ID do aplicativo colar em Key e copiar a chave secreta do aplicativo e colar em secret.
{% extends 'base.html' %}
{% load static %}
{% block title %}Inicio{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12 mb-3">
<h4 class="text-center">Bem vindo(a) {{ user.username }}</h4>
</div>
{% for a in backends.associated %}
{% if a.provider == 'facebook' %}
<div class="col-md-4 text-center">
<img src="{{ a.extra_data.picture.data.url }}" alt="" width="130" height="130" style="border-
radius:50%;">
</div>
<div class="col-md-8 social-container my-2">
<p>Logado via: {{ a.provider|title }}</p>
<p>Nome: {{ a.extra_data.name }}</p>
<p>Profile:<a href="{{ a.extra_data.profile_url }}">Link</a> </p>
</div>
{% endif %}
{% endfor %}
<div class="col-sm-12 mt-2 text-center">
<button class="btn btn-warning">
<a href="{% url 'logout' %}">Logout</a>
</button>
</div>
</div>
{% endblock %}
Raíssa Azevedo
O próprio arquivo de settings do projeto já possui dados de segurança, como o secret key que precisam ser
confidenciais.
• SQL Injection:
O django vem preparado contra SQL Injection, é um dos ataques mais comuns, através de um formulário de
entrada de dados, e quando clica no botão para fazer login e ocorre a combinação do dadof fornecido com o
salvo no banco de dados. Sites sem essa proteção, o cracker insere comandos que vão modificar o
comportamento do que está ssendo escrito, podendo até conceder permissão de adm.
urlpatterns = [
path('admin/', admin.site.urls),
]
Outra coisa que pode ser feita, é habilitar novos recursos de segurança, como:
# SECURE_SSL_REDIRECT = True
O ideal é ativar o ultimo recurso somente no momento da aplicação, ou a aplicação não irá rodar localmente no
momento do desenvolvimento.
SEÇÃO 07 – DISSECANDO O DJANGO USER MODEL
dir(User) ou help(User) para saber o que pode ser usado, ou olhar a documentação necessária.
help(manageruser.create)
ret = User.objects.all()
ret
<QuerySet [<User: teste>]>
>>> ret[0].username
'teste'
>>> ret[0].password
'pbkdf2_sha256$260000$r1nvLTJn6YnwHkpOcCWUhd$YQj kWMvriWB3J+5LWAkmB3kMwpap4SaOjs2NQrT2Vs='
Um Staff pode logar na área administrativa, mas não pode visualizar ou modificar nada. É preciso criar um superuser.
Ou seja, um usuário pode ser staff, mas não necessariamente é um super usuário.
1ª Forma:
class Post(models.Model):
autor = models.ForeignKey(User, verbose_name='Autor', on_delete=models.CASCADE)
titulo = models.CharField('Titulo', max_length=100)
texto = models.TextField('Texto', max_length=400)
def __str__(self):
return self.titulo
O User presente nessa forma, é o próprio do Django o que dificulta a customização da página administrativa.
2ª Forma:
A 2ª forma é utilizada quando fazemos a customização da área administrativa do Web Site:
AUTH_USER_MODEL = 'usuarios.CustomUsuario'
E no arquivo models:
from django.db import models
class Post(models.Model):
autor = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='Autor',
on_delete=models.CASCADE)
titulo = models.CharField('Titulo', max_length=100)
texto = models.TextField('Texto', max_length=400)
def __str__(self):
return self.titulo
Ou seja, precisa haver a indicação de mudança para o padrão customizado indicado anteriormente no arquivo de
settings.
3ª Forma:
Obs: É a forma mais indicada para introduzir uma área administrativa customizada.
O módulo de autentificação do Django tem um get_user_model para a executar a função customizada. Se tiver
sobrescrito, irá trazer a forma customizada, caso contrário ele irá exibir a área administrativa oficial.
class Post(models.Model):
autor = models.ForeignKey(get_user_model(), verbose_name='Autor', on_delete=models.CASCADE)
titulo = models.CharField('Titulo', max_length=100)
texto = models.TextField('Texto', max_length=400)
def __str__(self):
return self.titulo
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('titulo', 'autor')
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('titulo', '_autor')
Imagina que há um sistema com vários usuários, e você não quer que os demais tenham acesso aos dados dos demais
usuários.
Essa modificação é feita no Admin.py e ela entende que é pra mostrar somente os dados do usuário que está logado,
tudo relacionado a outro usuário, fica oculto.
Como pegar somente o dado da sessão que tá logado e ocultar a exibição de usuários na hora de fazer um novo Post.
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('titulo', '_autor')
exclude = ['autor', ]
Isso irá excluir a lista de autores que aparecia no módulo administrativo antes. Porém haverá um erro na hora de salvar
o novo post. Portanto é preciso fazer uma alteração no modo salvar do Post.
No admin.py essa alteração significa que a pessoa que está logada é a autora do Post. Dessa forma, o erro de salvar para
de ocorrer.
Como alterar o textos que indicam o nome da parte de administração:
O novo projeto de modificação de área Administrativa irá se chamar “Django User Model 3”
django-admin startproject djangousermodel3 .
django-admin startapp usuarios
1ª Forma:
from django.db import models
class CustomUsuario(AbstracBasetUser):
pass
def __str__(self):
return self.email
2ª Forma:
Todo o procedimento idêntico, entretanto, utilizando “AbstractUser”
class UsuarioManager(BaseUserManager):
use_in_migrations = True
class CustomUsuario(AbstractUser):
email = models.EmailField('E-mail', unique=True)
fone = models.CharField('Telefone', max_length=15)
is_staff = models.BooleanField('Membro da Equipe', default=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'fone']
def __str__(self):
return self.email
objects = UsuarioManager()
No create_user que indica o usuário padrão, o recomendado é deixar o setUp de staff como False. E deixar como True
somente nas configurações de Super User que indica o usuário administrador.
O campo objects= no final do código: Indica que todo o processo vai ser gerenciado pelo UsuárioManager.
Finalizando com o models.py, é preciso criar dois formulários para preenchimento da sessão de usuário.
Dentro do diretório da aplicação usuários criar um arquivo forms.py
No forms.py:
Serão criados os formulários de criação do usuário (UserCreateForm) e de alteração de usuário (UserChangeForm)
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUsuario
class CustomUsuarioCreateForm(UserCreationForm):
class Meta:
model = CustomUsuario
fields = ['first_name', 'last_name', 'fone']
labels = {'username': 'Username/E-mail'}
class CustomUsuarioChangeForm(UserChangeForm):
class Meta:
model = CustomUsuario
fields = ['first_name', 'last_name', 'fone']
Esses são os dois formulários necessários, um para criação e outro que permite alterar os dados.
@admin.register(CustomUsuario)
class CustomUsuarioAdmin(UserAdmin):
add_form = CustomUsuarioCreateForm
form = CustomUsuarioChangeForm
model = CustomUsuario
list_display = ['first_name', 'last_name', 'fone', 'is_staff']
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Informações Pessoais', {'fields': ('first_name', 'last_name', 'fone')}),
('Permissões', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
('Datas Importantes', {'fields': ('last_login', 'date_joined')}),
)
O fieldsets são todas as configurações padrões do Django que pedem os dados de cadastro do usuário. Há outros dados
que podem ser acrescentados.
As mudanças já ocorrem dentro do próprio terminal:
LOGIN E AUTENTICAÇÃO
Quer uma nova tela de autentificação, que seja diferente da oferecida pelo Django. O projeto utilizado será o mesmo.
Ir na parte de URLS:
urlpatterns = [
path('admin/', admin.site.urls),
path('contas/', include('django.contrib.auth.urls')),
path('', TemplateView.as_view(template_name='index.html'), name='index'),
]
Em seguida é preciso criar uma estrutura de templates para as telas de login. Dessa vez, o diretório de templates precisa
ser criado na raiz do projeto, ao invés da aplicação como nos projetos anteriores. Porque o que vai ser modificado é a
parte administrativa, e não o site.
Então, criar um diretório de templates na raiz do projeto.
Criar um arquivo html denominado base.html e fazer as modificações necessárias.
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Geek University</title>
<meta name="viewport" content="widthdevice=width, initial-scale=1, shrink-to-fit-no">
<link rel="icon" href="https://www.geekuniversity.com.br/static/images/favicon.4fcb819d32bf.ico">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"
id="bootstrap">
<link href="https://getbootstrap.com/docs/4.0/examples/sign-in/signin.css" rel="stylesheet">
</head>
<body class="text-center">
{% block content %}
{% endblock %}
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/4.00/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</body>
</html>
Garantir ter adicionado o favicon, o css e o Javascript. Por se tratar da página base. Adicionar os blocos de conteúdo no
body padrões do Django.
Dentro do diretório templates, criar o index.html
Nas configurações da pagina “index” indicar que se o usuário for anônimo colocar uma área para Login
E se o usuário tiver autenticado exibir a mensagem de “Bem Vindo” e o botão de logoff
{% extends 'base.html' %}
{% block content %}
<div class="container">
<h1>Geek University</h1>
{% if user.is_anonymous %}
<a class="btn btn-primary" href="{% url 'login' %}">Login</a>
{% else %}
<div class="alert alert-primary" role="alert">
Seja bem vindo(a), {{ user.get_full_name }}!
</div>
<a class="btn btn-primary" href="{% url 'logout' %}">Logout</a>
{% endif %}
</div>
{% endblock %}
{% extends 'base.html' %}
{% block content %}
<form class="form-signin" method="post" autocomplete="off">
{% csrf_token %}
<img class="mb-4" src="https://www.geekuniversity.com.br/static/images/favicon.4fcb819d32bf.ico" alt=""
width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Informe seus dados</h1>
LOGIN_REDIRECT_URL = 'index'
LOGOUT_REDIRECT_URL = 'index'