O que é?
Framework web baseado em python, ou seja, uma caixa de ferramentas para criação web.
Ler: Documentation/First Steps
PIP é o instalador de pacotes python VirtualEnv: me isola do sistema operacional. Só deve instalar o django dentro de uma virtual env, pois assim é possível usar várias versões de django para trabalhar em vários projetos Todo desenvolvimento em Python tem o conceito de ambiente virtual. (virtualenv) É uma pasta com vários arquivos que isolam o sistema Usar o pip: só no myenv. Quando dentro de uma virtualenv o python já é python 3.6.
lista o conteúdo do arquivo:
eli@PC:~$ cat
Entrar no ambiente virtual:
eli@PC:~$ source myenv/bin/activate
**ou**
eli@PC:~$ . myenv/bin/activate
Criar uma pasta para o projeto:
eli@PC:~$ mkdir projetoteste
Entrar nela:
eli@PC:~$ cd projetoteste
Criar uma virtual env:
eli@PC:~$ python3 -m venv <nome do ambiente virtual>
Se não funcionar:
eli@PC:~$ sudo apt-get install python3.6-venv
Ativar o ambiente virtual:
eli@PC:~$ source <nome do ambiente virtual>/bin/activate
Install Django:
eli@PC:~$ pip install django
Criar o projeto django:
eli@PC:~$ django-admin startproject <nome do projeto>
OBS: para criar um projeto dentro da pasta corrente usar o <.>
Roda o projeto no servidor local (apenas para os teste locais)
eli@PC:~$ python manage.py runserver
__init__.py
transforma todas as pastas em um pacote python
settings.py
mais importante do projeto
urls.py
onde ficam as URLs, vem apenas com a admin habilitada
wsgi.py
aponta para um servidor, entrepoint, a aplicação começa nele, configurar o servidor
manage.py
tirar proveito do que ele fornece, não será necessário modificar nada nele
import os
ver os caminhos do sistema operacional, é um biblioteca
BASE_DIR
tem a url base do projeto
SECRET_KEY
é preciso manter em segurança, pois faz a criptografia de senhas
DEBUG
se está modo de desenvolvimento marca true, senão false, se não expõe informações sensíveis do projeto
ALLOWED_HOSTS
endereços que o django vai responder, é o domínio. Pois o django só responde requisições que vem desse domínio
INSTALLED_APPS
aplicações que já vem instaladas no django
MIDDLEWARE
camadas que o django passa, segurança, sessão, etc
ROOT_URLCONF
aponta as URLs principais do django
TEMPLATES
são configurações de templates que já vem com o django
WSGI_APPLICATION
aponta para a variável application dentro do wsgi
DATABASE
configuração de banco de dados
AUTH_PASSWORD_VALIDATORS
validadores de senha
LANGUAGE_CODE
linguagem usada
TIME_ZONE
Local onde roda, ex: America/Sao_Paulo
USE_I18N
Se usa internacionalização
USE_L10N
Para regionalização
USE_TZ
Se quer usar time zone ou não
STATIC_URL
pasta base do static
O que é uma requisição web?
É a solicitação de coisas para o servidor, de forma bem básica
Como funciona as requisições?
Com o protocolo http
- WEB SERVER
servidor que hospeda a aplicação - WSGI
descobre onde está os settings - REQUEST (MIDDLEWARE)
validação da requisição para saber se é seguro - URL RESOLUTION (ROOT-URLCONF) lista das urls
- VIEW (views.py)
a função que vai processar a response, pode precisar ir para qualquer um desses, o que ela precisar fazer:- MODEL (models.py)
- MANAGERS
- DATABSE
- TEMPLATE (MIDDLEWARE)
página (html, css, js, imagens) - RESPONSE
quando o template está pronto ele retorna uma response - WSGI
volta para wsgi
O que são URLs?
São os caminhos por onde a requisição vai passar.
No django elas estão na urls.py (porteiro)
Antes ela passa pela validação e segurança
Qual a função?
Informar o que a request precisa
O que mudou da versão 1.x para a versão 2.x?
Na 2.x você não precisa escrever necessariamente suas urls com regex. Agora é possível usar funções nativas
-
Adiciona a nova url em urls.py no ulrpatterns
Na função path o primeiro parâmetro é a nome da url, depois tem a view, que faz o processamento da url. Por padrão o admin já está configurada (é uma aplicação).
exemplo
path(‘hello/’, hello)
-
Ainda não existe a função hello(), para criá-la, cria um arquivo com o nome views.py. Nele se faz as funções que serão chamadas na view.
exemplo
def hello(): pass
-
Para que o urls.py reconheça essa nova função, é só fazer o import.
exemplo
from .views import hello
-
Mas o django reclama, pois ainda não passamos nenhum parâmetro para essa função. Ainda assim, o django tenta passar um parâmetro que é a request.
exemplo
def hello(request):
-
Agora a questão é que a função não está retornando um objeto HttpResponse. Pois toda view retorna ele.
exemplo
from django.http import HttpResponse def hello (request): return HttpResponse(‘Olá Mundo’)
O que são VIEWS (FUNCTIONS)?
É a ação que executa alguma coisa da request. Ela pode ser uma classe (CLASS_BASE_VIEW) ou uma função, vamos ver a principio como função
def fname(request, ...):
statements
part | description |
---|---|
def |
caracteriza uma função em PYTHON |
fname |
nome da função |
() |
parâmetros da função |
request |
principal parâmetro da função django |
... |
demais parâmetros da função |
: |
inicio dos comandos |
statements |
comandos |
É possível realizar chamada de outras funções dentro do views.py sem precisar apontá-las no urls.py. Dessa forma, a função terá um escopo local.
As views para executar o papel precisa acessar os MODELs. Os prjetos são compostas de APP's. E cada APP executa uma função específica do projeto.
(myvenv) eli@PC:~$ python manage.py startapp clientes
Cria a estrutura da aplicação de gestão de clientes
Nela Temos os arquivdos de:
__init__.py
que prova que isso é um pacote python
pra registrar os models para aparecer no admin do django
onde se desenvolve os models
é possível ter views próprias dessa aplicação
Models são classes que descrevem os modelos do meu negócio. É onde a inteligência estará embutida.
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
age = models.IntegerField()
Na primeira linha, o django já provê um import de uma classe básica de modelos, nela o django concentra boa parte da inteligencia de automação. Essa classe Person já herda de Model. Esse é um exemplo de classe que cria dois atributos de primeiro e último nome. Esse atributos estarão correlacionados com o banco de dados pelos campos models
A depois de criar o as classes que serão usadas no model, cria-se o banco de dados. No settings, por padrão usa-se o db.sqlite3. Isso está configurado no settings. Quando se cria o DB a composição dele é baseada nas migrações (migrations). Ela é uma classe que descreve o que vai ter no DB, as tabelas, os registros.
As aplicações que vem junto com o django também precisam ter suas migrações. Para isso usa-se o comando:
eli@PC:~$ python manage.py migrate
Depois desse comando, o django cria tudo que existe nas aplicações e precisa de um DB. Mas as aplicações novas não são criadas automaticamente, é preciso registra-las em INSTALLED_APPS. Basta apenas colocar o nome dela. Depois usa-se o comando:
eli@PC:~$ python manage.py makemigrations
Esse comando cria a migration da aplicação que estamos adicionando. Nesta nova migration, é possível ver como é criada a tabela no DB. Esse comando só cria o arquivo para ser aplicado no DB. Então para aplicar no DB usa-se o comando anterior.
O Admin é um aplicação que o Django provê que automatiza a criação de Backends. Implementa o OAuth e outras validações. Para comecar a usa-lo é preciso criar os usuários. Com o seguinte comando:
eli@PC:~$ python manage.py createsuperuser
Depois escolhe o user name, email e senha. Depois de logar o django acessa a sessão de administração. Ele já tem um sistema de gestão de grupos e usuários por padrão. O primeiro é criado por linha de comando, mas o sengundo pode ser criado nessa tela. Grupos e usuários são models que o django já traz pronto. Além de poder administrar os models do django é possível administrar os nossos models. Isso é feito no arquivo admin.py do model que criamos. Dessa forma:
from django.contrib import admin
from .models import Person
admin.site.register(Person)
Depois que isso é feito, aparecerá o nome da aplicação (clientes) e o model que foi criado (Person). Quando é criado um Person nessa aplicação, o nome que aparecerá será Person object(1). Pois no model que criamos é necessário criar uma função que sete o nome do objecto Person a ser criado com o nome da pessoa, dessa forma:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
age = models.IntegerField()
salary = models.DecimalField(max_digits=5, decimal_places=2)
bio = models.TextField()
def __str__(self):
return self.first_name
Em um cenário normal as views retornam um template. Por enquanto nossas VIEWS estão retornando um texto simples. O que não é um cenário realista. O django já provê a renderização de templates. Que é basicamente pegar o dado que a gente vai fornecer transformar isso numa RESPONSE, colocar as variáveis que forem necessárias e manda de volta pro navegador. Para isso é preciso definir no settings onde iremos guardar nossos TEMPLATES. Isso é feito na variável DIRS. Cria-se uma pasta com os meus templates, esta tem que estar ao lado de manage.py.
TEMPLATES = [
'DIRS': ['<nome da pasta>']
]
O primeiro arquivo é o index.html (Isso é um template). Após criar o template, este deve ser carregado dentro da view. Para isso usa-se a função render. Que vai ler o template e transformar numa response.
from django.shortcuts import render
def hello(request):
return render(request, 'index.html')
Quando vai mandar de volta o template ele submente a response a todas as validações iniciais (Middleware)
Quando for necessário ler uma variável que tem origem em uma view, usa-se para isso mais um parâmentro do render, ele recebe uma variável que é lida com a linguagem de template jinja.
from django.shortcuts import render
def fname2(request, nome):
idade = lerDoBanco(nome)
return render(request, 'pessoa.html', {'v_idade': idade})
Essa variável v_idade estará disponível para ser lida dentro do template
<body>
A pessoa foi encontrada, ela tem {{ v_idade }} anos
</body>
Esse abre e fecha parênteses indica que estamos usando a linguagem de templates do django (jinja). Ainda é possível criar lógicas de programação (códigos):
<body>
{% if v_idade > 0%}
A pessoa foi encontrada, ela tem {{v_idade}} anos
{% else %}
Pessoa não encontrada
{% endif %}
</body>
Não sendo uma lógica de negócio é permitido colocar no template, é apenas uma lógica de usuário.
Até agora a gente viu TEMPLATES que são arquivos não estáticos. Pois ele pode ter variáveis, ifs, fors. Enfim, se ele vai ser processado pelo django e entregue na response, será considerado arquivo não estático. Logo, além dos htmls, precisamos entregar arquivos como CSS, JS, Imagens, etc.
No settings existe uma variável chamada STATICFILES_DIRS. Nela se define o nome do seu diretório que contém os arquivos estáticos.
STATICFILES_DIRS = [
'<nome do diretório>',
]
O projeto vai procurar no diretório raiz. No mesmo nível de TEMPLATES. Pra carregar no TEMPLATE usa-se a template tag:
{% load static %}
Depois disso é possível carregar os arquivos no head
<link rel="stylesheet" href="{% static '<nome do arquivo>' %}">
Assim como os arquivos estáticos, esses arquivos tem pode difinição que ele será servido da forma que ele está, ele não será processado. A diferença entre os arquivos de media e os arquivos estáticos é que estes são postos no sistema pelo desenvolvedor, já aqueles são carregados pelo usuário. São exemplos: fotos perfil, documentos, vídeos.
No arquivo settings.py:
# NOME DA URL QUE SERÁ USADA
MEDIA_URL = '/<nome da url(ex. media)>/'
# PASTA ONDE SERÃO SALVOS OS ARQUIVOS DE MEDIA
MEDIA_ROOT = 'media'
Cria-se a pasta para salvar os arquivos ao lado das demais. Para pode usar os arquivos de media, usa-se um model que tenha esse campo. No model criado, PERSON, adicionar um campo de photos:
# ESSE PRIMEIRO PARÂMETRO PERMITE SALVAR EM UMA SUBPASTA DE MEDIA
# O SEGUNDO E TERCEIRO, PERMITEM QUE ESSE CAMPO SEJA OPCIONAL, SERVE PARA OS DEMAIS TAMBÉM
photo = models.ImageField(upload_to='clients_photos', null='true', blank='true')
Agora cria-se o campo no banco, pois toda vez que houver uma alteração dentro dos MODELS é preciso migra-las para o banco.
eli@PC:~$ python manage.py makemigrations
Depois aplica-se essas migrações
eli@PC:~$ python manage.py migrate
Sempre que utilizar um campo de imagem no django pode ser necessário instalar a biblioteca Pillow que manipula imagem.
(venv) ~/eli@PC:~$ pip install Pillow
Pode ocorrer de os nomes dos arquivos de imagens serem iguais, automaticamente o django faz um rename, mas é possível criar uma função que faça essa manipulação no upload_to, deverá estar no MODEL.
Quando você tentar abrir essa imagem upada, será exibida um Erro 404, pois o servidor não está pronto para servir essa imagem. Um técnica boa é enviar essa imagem para a Amazon.
É uma forma de servir os arquivos de media durante o desenvolvimento
O django não serve arquivos estáticos nem de media. Ele cuida de arquivos python. Quando for fazer o deploy, é importante ver uma forma mais profissional de servi-los.
Mas é possível fazer uma "gambiarra" para que, em tempo de desenvolvimento, você possa ver seus arquivos de imagens.
No urls.py
from django.conf import settings
from django.conf.urls.static import static
# USA-SE ESSA FUNÇÃO ESTÁTICA PARA QUE O DJANGO ADICIONE A URL QUE FOI CONFIGURADA PARA MEDIA NO SETTINGS, ASSIM COMO A PASTA QUE INDICA ONDE ESTÁ O ARQUIVO ENVIADO
urlpatterns = [] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
C: Create
R: Read
U: Update
D: Delete
É preciso criar as URLs da nossa aplicação. Pois se todas ficarem aculadas no arquivos urls.py principal, acaba virando uma bagunça. Então para isso cria-se um arquivo urls.py dentro da aplicação de clientes no mesmo nível dos demais arquivos. clients/urls.py
from django.urls import path
from .views import persons_list
urlpatterns = [
# EXEMPLO DE USO
path('list/', persons_list)
]
Criando a view da aplicação client clients/views.py
from django.shortcuts import render
# EXEMPLO DE USO
def persons_list(request):
return render(request, 'pessoa.html')
urls.py
#[...]
# INCLUI URLS DE OUTRAS APLICAÇÕES
from django.urls import include
# IMPORTA DESSA FORMA AS URLS DA APLICAÇÃO DE CLIENTES
from clientes import urls as clients_urls
urlpatterns = [
path('person/', include(clients_urls)),
]
Lendo clientes no banco de dados.
O django possibilita a manipulação/ler de dados do banco através de manager. Por padrão todo model já vem com um manager chamado objects
clients/views.py
from django.shortcuts import render
# IMPORTANDO PERSON
from .models import Person
# EXEMPLO DE USO
def persons_list(request):
# LENDO
# ESSE COMANDO É EQUIVALENTE A select * from person NO SQL
persons = Person.objects.all()
# OUTRAS QUERYS
# persons = Person.objects.get(id=1)
# PASSANDO A VARIÁVEL PARA O TEMPLATE
return render(request, 'person.html', {'persons': persons} )
Usando a linguagem de template do Django
<body>
<ul>
{% for person in persons %}
<li>{{ person.first_name }}</li>
{% endfor %}
</ul>
</body>
Conceito de formulário, iremos contruir todo o caminho que a requisição irá passar. Ao invés de pedir informações para o banco, iremos envia-las para o banco de dados.
clientes/urls.py
from .views import persons_new
urlpatterns = [
# É POSSÍVEL DAR APELIDOS PARA AS URLS
path('new/', persons_new, name="person_new"),
]
clientes/views.py
def persons_new(request):
pass
Quando a url entregar a view, esta vai entregar um formulário a ser preenchido. Então criamos um template com o nome person_form.html.
<body>
<!-- a classe action server para referenciar o que o botão irá fazer -->
<form action="{% url 'person_new' %}" method="POST">
<!--O botão tem que ter o tipo submite, que enviarar todo o form para a url informada e depois para o servidor-->
<button type="submit"></button>
</form>
</body>
Documentação para o django forms
Usaremos o ModelForm que baseado no model irá cria todas as validações do formulário
Criando a classe dentro de um arquivo forms na aplicação
clientes/forms.py
from django.forms import ModelForm
from .models import Person
# ESSA CLASSE HERDA DO MODELFORM
class PersonForm(ModelForm):
# CRIANDO UMA SUBCLASSE PARA INDICAR QUAL MODEL SERÁ A REGRA DE NEGÓCIOS PARA ESSE FORM E OS CAMPOS PARA O MESMO
class Meta:
model = Person
# SÃO OS CAMPOS QUE TEMOS NO MODEL
fields = ['first_name', 'last_name', 'age', 'salary', 'bio', 'photo']
clientes/views.py
Importa-se o form para dentro da view. Existem dois momentos que são necessários tratar. O primeiro é quando enviamos um form novo para nossa página.
from .forms import PersonForm
def persons_new(request):
# PRIMEIRO MOMENTO, USANDO O request.POST, QUANDO O CLIENTE CLICAR EM SALVAR SERÁ ENVIDADO UM FORMULÁRIO COM OS DADOS PREENCHIDOS. CASO O CLIENTE ESTEJA ABRINDO A PÁGINA PELA PRIMEIRA VEZ, VOCÊ PODE MANDAR UM form VAZIO, USANDO O SEGUNDO PARÂMETRO None
form = PersonForm(request.POST, none)
# É PRECISO ENTREGAR ESSE form LÁ PARA A PÁGINA. ALÉM DISSO, QUERO INSERIR DENTRO DO html A VARIÁVEL form.
return render(request, 'person_form.html', {'form': form})
templates/person_form.html
<body>
<form action="{% url 'person_new' %}" method="POST" enctype="multipart/form-data">
<!--importante sempre incluir em todo formulário a variável csrf_token, que é uma proteção para formulário provida pelo django. Para evitar que esses formulários sejam manipulados do lado do cliente-->
{{% csrf_token %}}
<!--exibindo a variável enviada-->
{{% form %}}
<button type="submit">Salvar</button>
</form>
</body>
Para concluir é preciso validar o formulário
clientes/views.py
from .forms import PersonForm
def persons_new(request):
form = PersonForm(request.POST, none)
# VALIDANDO, SE FOR VÁLIDO, ENTÃO RETIRA O FORMULÁRIO DA REQUISIÇÃO E TRANSFORMA EM UM OBJETO SALVANDO-O.
if form.is_valid():
form.save()
return render(request, 'person_form.html', {'form': form})
Depois de salvar no BD, vamos redirecionar nossa página para uma outra usando uma função chamada REDIRECT
Para salvar as imagens. É preciso fazer outra verificação. Pegando o request.FILES no PersonForm(). E adicionar no formulário um enctype="multipart/form-data"
from .forms import PersonForm
from django.shortcuts import render, redirect
def persons_new(request):
form = PersonForm(request.POST, request.FILES, none)
if form.is_valid():
form.save()
# MANDA O USUÁRIO PARA UMA URL
return redirect('person_list')
return render(request, 'person_form.html', {'form': form})
Uma ultima coisa é adicionar um link para cadastrar um novo cliente em person.html usando:
<a href="{% url 'person_new' %}">Novo Cliente</a>
Como tudo começa pelas urls...
clientes/urls.py
from .views import persons_update
urlpatterns = [
path('update/<int:id>', persons_update, name='person_update'),
]
Essa url chama uma view da aplicação
clientes/views.py
def persons_update(request, id):
person = get_object_or_404(Person, pk=id)
form = PersonForm(request.POST or None, request.FILES or None, instance=person)
if form.is_valid():
form.save()
return redirect('person_list')
return render(request, 'person_form.html', {'form': form})
Esta função da view, recebe como parâmentro o id da pessoa que será atualizada. O primeiro passo é buscar a pessoa no banco com a função get_object_or_404, essa busca é pela chave primária (id). Logo após, instaciamos o formulário com os dados recuperados da pessoa.
A validação do formulário é feita como nas outras funções, depois o fuxo é recirecionado para a lista de pessoas. Caso o formulário não seja válido, a requisição retorna o prórpio formulário com a instância da pessoa.
No template person.html precisamos "linkar" as pessoas, para que quando clicando nelas seja possível alterá-las. Para tanto usamos o jinja com a url person_update passsando também o id do objeto.
<body>
<ul>
{% for person in persons %}
<li><a href="{%url 'person_update' person.id%}">{{ person.first_name}}</a></li>
{% endfor %}
</ul>
<br>
<a href="{% url 'person_new' %}">Novo Cliente</a>
</body>
Uma última coisa a ser feita é retirar o action do botão no person.html, pois o django irá referenciar a url que está sendo usada. Por exemplo, quando implementamos o formulário queriamos que ao clicar no botão salvar fosse criado uma nova pessoa, contudo agora queremos atualizar uma.
Tudo começa nas urls
clientes/urls.py
from .views import persons_delete
urlpatterns = [
path('delete/<int:id>', persons_delete, name='person_delete'),
]
clientes/views.py
def persons_delete(request, id):
person = get_object_or_404(Person, pk=id)
if request.method == 'POST':
person.delete()
return redirect('person_list')
return render(request, 'person_delete_confirm.html', {'person': person})
Uma das formas de criar essa view seria usar o form para confirmar a exclusão, contudo iremos usar apenas o primeiro nome do objeto. Logo, a primeira coisa a ser feita é buscar o objeto com a função get_object_or_404. Se quando usarmos a url de deleção sua origem foi de um método POST, que é o caso do template person_delete_confirm.html, deletamos o objeto e redirecionamos para a lista de pessoas. Caso a origem não seja de um método POST redirecionamos para o template de confirmação, que detém o método POST. Podemos ver esse fluxo dessa forma:
template/person.html
Criamos o link para deletar
<body>
<ul>
{% for person in persons %}
<li>
<a href="{%url 'person_update' person.id%}">{{ person.first_name}}</a>
<a href="{%url 'person_delete' person.id%}">deletar</a>
</li>
{% endfor %}
</ul>
<br>
<a href="{% url 'person_new' %}">Novo Cliente</a>
</body>
Esse formulário envia por defaut o método GET, portanto não entra no teste. Então será chamado o template:
template/person_delete_confirm.html
body>
<h1>Deseja exclui? {{ person.first_name }}</h1>
<form method="POST" enctype="multipart/form-data">
{%csrf_token%}
<button type="submit">Delete</button>
</form>
</body>
Observe que o método agora é POST, como esse formulário foi chamado pela view, ele retornará para a mesma e esta excluirá o objeto. Por último a requisição irá para a listagem de pessoas.