Curso Intro django
Posted on Sáb 03 Outubro 2020 in tutorial
Dica
para ler o documento
$> # quer dizer que o comando é executado no SHELL do seu sistema operacional.
O HTTP
Não adianta conhecer a ferramenta se não conhecemos o problema
HTTP - Protocolo de Transferência de Hipertexto, é a base de comunicação com a internet ou "world Wide Web".
- Outras fontes:
"Request" vs "Response"
Python - Preparando seu ambiente
Ambiente virtual
O que é um ambiente virtual ??
O módulo venv fornece suporte para a criação de “ambientes virtuais” leves com seus próprios diretórios de site, opcionalmente isolados dos diretórios de site do sistema. Cada ambiente virtual possui seu próprio binário Python (que corresponde à versão do binário usado para criar esse ambiente) e pode ter seu próprio conjunto independente de pacotes Python instalados nos diretórios do site.
—fonte "Documentação do Python sobre ambientes virtuais: https://docs.python.org/pt-br/3/library/venv.html#an-example-of-extending-envbuilder
Diretório de trabalho
Para facilitar, fins didáticos, vamos criar o um diretório e dentro deste iremos ter outros 2 com o ambiente virtual e projeto Django.
Criar um diretório de trabalho django_necto_fatec
$> mkdir django_necto_fatec
entre no diretório de trabalho
$> cd django_necto_fatec
Criando o "ambiente virtual"
Crie o diretório do seu virtual enviroment utilizando o "venv" do Python, com o nome de "django_intro_env"
$> python -m venv django_intro_env
Nota
Sobre o ambiente virtual em https://docs.python.org/pt-br/3/library/venv.html
"Virtual Environment" - Super Gemeos Ativar
estando "dentro" do diretório django_necto_fatec execute os passos abaixo.
Para linux
$> source django_intro_env/bin/activate
Aviso
No WINDOWS ...
$> django_intro_env\scripts\activate.bat
O ambiente virtual ficará ativo enquanto a sessão do shell estiver ativa.
Se outra sessão for aberta, é necessário ativar o ambiente virtual para aquela sessão.
Para sair do seu ambiente virtual
$> deactivate
Hierarquia e organização final dos diretórios
Até agora, devemos ter a seguinte estrutura de diretórios.
django_necto_fatec ├── django_intro_env │ ├── bin │ ├── include │ ├── lib │ └── pyvenv.cfg
Verifique as bibliotecas instaladas
$> pip list --local
resultado esperado ...
Package Version ---------- ------- pip 20.2.3 setuptools 49.2.1
RESUMO
para o Linux
1. $> mkdir django_necto_fatec
2. $> cd django_necto_fatec
3. $> python -m venv django_intro_env
4. $> source django_intro_env/bin/activate
5. $> pip list --local # somente para verificar se esta tudo ok.
para o Windows
1. $> mkdir django_necto_fatec
2. $> cd django_necto_fatec
3. $> python -m venv django_intro_env
4. $> django_intro_env\scripts\activate.bat
5. $> pip list --local # somente para verificar se esta tudo ok.
saída esperada para ambos os casos ...
Package Version ---------- ------- pip 20.2.3 setuptools 49.2.1
Instalando o Django no ambiente virtual
A intenção é instalar o Django no ambiente virtual criado anteriormente.
Para isso verifique se o seu prompt de comando, indica que seu ambiente virtual está ativo.
O ambiente virtual ativo é indicado no seu prompt de comando como abaixo
(django_intro_env) $ _
Não importa o diretório que esteja, o ambiente virtual estará sempre ativo dentro daquela sessão (do shell).
Sendo o Django uma biblioteca (lib) Python, podemos instalá-lo com o pip, como mostrado abaixo.
$> pip install django
Nota
- Site do Django em português - https://docs.djangoproject.com/pt-br/3.2/
- Saiba mais sobre o pip em https://pypi.org/project/pip/
O Django está instalado ?
$> pip list --local
ou
$> pip freeze
Dica
repare na saída dos 2 comandos
Iniciando um projeto Django
- Criar um diretório para o projeto - com o nome de django_intro_proj
- Criar um projeto Django chamado djproj
Crie o diretório do seu projeto Django, e "entre" no diretório.
$> mkdir django_intro_proj
$> cd django_intro_proj
Dentro do diretório do seu projeto execute
$> django-admin startproject djproj
$> cd djproj
A arvore de diretórios deve ter a seguinte hierarquia:
django_necto_fatec # Diretorio raiz projeto + Python environment ├── django_intro_env # Diretório Python │ ├── bin │ ├── include │ ├── lib │ └── pyvenv.cfg └── django_intro_proj # Diretório do projeto django (Código) └── djproj ├── djproj │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py # gerenciador do Django - indica a raiz do meu projeto django
Dica
o diretório do ambiente virtual poderia ser criado em qualquer outro local do seu sistema de arquivos.
resumo:
1. $> mkdir django_intro_proj
2. $> cd django_intro_proj
3. $> django-admin startproject djproj
4. $> cd djproj
Encontrar o arquivo manage.py
teste: já funciona?
$> python manage.py runserver 8080
Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). ... <podem aparecer outras informações aqui> ... July 21, 2021 - 01:24:44 Django version 3.2.5, using settings 'djproj.settings' Starting development server at http://127.0.0.1:8080/ Quit the server with CONTROL-C.
Aviso
As informações emitidas pelos comandos do Python/Django são bastante claras e objetivas
Importante acostumar-se a ler o que é impresso, sempre útil.
Abra um navegador Web no endereço indicado na mensagem do Django - http://127.0.0.1:8080/
O resultado esperado é mostrado abaixo - o "foguetinho do Django"
Dica
Quando o runserver é executado sem a porta, a porta padrão é a 8000.
Então se executado
$> python manage.py runserver
a url deve ser http://127.0.0.1:8000/
Django APP
vamos criar uma aplicação chamada app_intro
O objetivo desta aplicação Django é somente para podermos acessar a requisição feita por um navegador Web na sua aplicação.
- O que sua aplicação recebe ?
- Como chegam os dados ?
Na raiz do seu projeto execute o comando abaixo
Dica
A raiz do projeto Django é onde está o arquivo manage.py
$> python manage.py startapp app_intro
Repare que o Django criou o diretório "app_intro" e dentro deles vários outros arquivos no caminho django_necto_fatec/django_intro_proj/djproj/ e sua árvore de diretórios deve estar parecida com o esquema abaixo.
djproj ├── app_intro │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── migrations │ ├── models.py │ ├── tests.py │ ├── urls.py # !! este arquivo deve ser criado !!! │ └── views.py # editar este arquivo. ├── djproj │ ├── ... # existem outros arquivos │ ├── urls.py # iremos editar este arquivo │ └── wsgi.py └── manage.py
Para que o Django possa responder a uma requisição em uma url precisamos "avisar" ao Django o que fazer quando a url for endereçada, do contrário ele retornará um erro HTTP 404.
- Edite o arquivo:
- django_necto_fatec/django_intro_proj/djproj/app_intro/views.py
# app_intro/views.py - django_necto_fatec/django_intro_proj/djproj/app_intro/views.py
from django.shortcuts import render
from django.http import HttpResponse
def print_reqs(request):
print (request)
return HttpResponse('hello world')
- Edite o arquivo:
- django_necto_fatec/django_intro_proj/djproj/urls.py
# djaproj/urls.py - django_necto_fatec/django_intro_proj/djproj/urls.py
from django.contrib import admin
from django.urls import include, path
from app_intro.views import print_reqs
urlpatterns = [
path('print_get_post_meta/', print_reqs, name='print_get_post_meta'),
path('admin/', admin.site.urls),
]
E então verifique se o servidor continua rodando ou execute
$> python manage.py runserver
Com o seu navegador Web, acessa a url inicial
Objetos Http
Vamos utilizar nossa view para visualizar um pouco da requisição HTTP ou HTTP request
Mais adiante iremos entrar em detalhes sobre as partes do Django, por hora basta saber que uma view nada mais é que uma função Python que recebe um parâmetro com os dados do request e sempre deve retornar uma resposta válida para o HTTP.
Analisando rapidamente a view app_intro,views.py
django_necto_fatec/django_intro_proj/djproj/app_intro/views.py
A view é uma função Python que recebe como primeiro parâmetro um objeto do tipo HttpRequest Na função abaixo é o parâmetro request da view print_reqs
Nota
leia mais em https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.HttpRequest
Outro ponto importante da função, é que esta deve retornar um objeto HttpResponse. Na função abaixo, este objeto é criado instanciando o objeto HttpResponse()
# app_intro/views.py - django_necto_fatec/django_intro_proj/djproj/app_intro/views.py
from django.shortcuts import render
from django.http import HttpResponse
def print_reqs(request):
''' View Hello World '''
print (request)
return HttpResponse('hello world')
Vamos editar esta view para nos mostrar mais sobre o objeto HttpRequest
# app_intro/views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def print_reqs(request):
'''
Imprime requisições POST, GET e META (variaveis do cabeçalho)
'''
print ("\n-------META--------------\n")
print(request.META)
print ("\n-------REQUEST--------------\n")
print (request)
print ("\n-------REQUEST POST--------------\n")
print (request.POST)
print ("\n-------REQUEST GET--------------\n")
print (request.GET)
return HttpResponse('olá mundo')
Os prints da view devem aparecer no sessão da linha de comando onde foi iniciado o servidor do Django e deve se parecer com algo como abaixo
-------REQUEST-------------- <WSGIRequest: GET '/print_get_post_meta'> -------REQUEST POST-------------- <QueryDict: {}> -------REQUEST GET-------------- <QueryDict: {}> -------META-------------- {'TERM_SESSION_ID': 'w0t0p0:C19AB7E2-6734-4EF7-8618-F1CF88CA8284', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.igyfZUFvo0/Listeners', 'LC_TERMINAL_VERSION': '3.4.8', 'COLORFGBG': '15;0', 'ITERM_PROFILE': 'Default', 'XPC_FLAGS': '0x0', 'PWD': '/Users/cadu/projs/django_necto_fatec/django_intro_proj/djproj', 'SHELL': '/bin/zsh', '__CFBundleIdentifier': 'com.googlecode.iterm2', 'TERM_PROGRAM_VERSION': '3.4.8', 'TERM_PROGRAM': 'iTerm.app', 'PATH': '/Users/cadu/projs/django_necto_fatec/django_intro_env/bin:/usr/local/opt/tcl-tk/bin:/Applications/Postgres.app/Contents/Versions/12/bin:/usr/local/opt/python/libexec/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin:/opt/X11/bin:/Library/Apple/usr/bin:/Applications/Post ...
O que fizemos aqui foi imprimir o Objeto HttpRequest <WSGIRequest: GET '/print_get_post_meta'>
Em seguida temos o dicionário com o conteúdo do POST (caso houvesse uma submissão via POST - e. um formulário) <QueryDict: {}>
O dicionário do GET onde poderiam estar os parâmetros partes de uma url - ex.: https://example.com/caminho/pagina?nome=carlos&color=blue representando pelo <QueryDict: {}>
Por último temos o conteúdo douto atrib META, que contém todos os dados do cabeçalho . Veja uma lista de exemplos em https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.HttpRequest.META
PERIGO!
ADICIONAR NO CONTEÚDO
- SE Nao tem nome ("name"), nao é enviado
- Verbos HTTP
- MultiValueDict / Dict
- Aquivos ESTATICOS nao passam pelo DJANGO !
- tudo que recebeo no request é string
- o form do Django valida os tipos e me da o tipo do dado
- vale a pensa usar sempre o form do Django
Dados no dicionário do GET
Simplesmente acesse a url da view passando alguns parâmetros como query string
ex.: http://127.0.0.1:8000/print_get_post_meta/?data=2020-07-11&var=teste&data1=1&data2=2
Os prints da view devem apresentar algo como abaixo
-------REQUEST-------------- <WSGIRequest: GET '/print_get_post_meta/?data=2020-07-11&var=teste&data1=1&data2=2'> -------REQUEST POST-------------- <QueryDict: {}> -------REQUEST GET-------------- <QueryDict: {'data': ['2020-07-11'], 'var': ['teste'], 'data1': ['1'], 'data2': ['2']}> [22/Jul/2021 02:45:08] "GET /print_get_post_meta/?data=2020-07-11&var=teste&data1=1&data2=2 HTTP/1.1" 200 500
Repare que os dados aprecem no objeto (dicionário) QueryDict GET
Dados no dicionário do POST
Para visualizar os dados de um POST, iremos precisar de um formulário com o botão de submit.
Você poderia abrir qualquer arquivo HTML no seu navegador Web e "apontar" o formulário (<form action="...url...">) para o endereço da view, mas definindo o método como POST
por exemplo crie um arquivo html com o conteúo abaixo.
Temos 2 formulários que aponta para a url da nossa view de demonstração.
Mas o primeiro usa o method=post e o outro o method=get.
Submeta e veja a saída dos prints da view.
<html>
<body>
<h1>Formulário POST</h1>
<form action="http://127.0.01:8000/url_intro/" method="post">
<label for="id_nome">nome:</label>
<input type="text" id="id_nome" name="nome"><br><br>
<label for="id_sobrenome">Sobrenome:</label>
<input type="text" id="id_sobrenome" name="sobrenome"><br><br>
<input type="submit" value="Submit">
</form>
<hr>
<h1>Formulário GET</h1>
<form action="http://127.0.01:8000/url_intro/" method="get">
<label for="id_nome">nome:</label>
<input type="text" id="id_nome" name="nome"><br><br>
<label for="id_sobrenome">Sobrenome:</label>
<input type="text" id="id_sobrenome" name="sobrenome"><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
O Framework Web "Django"
Django - The web framework for perfectionists with deadlines.
Alguns sites onde o Django é usado
Partes do Django
URL Configuration
Views
Template
Models
Django Admin
Django Settings
Middlewares
Webserver wsgi
PERIGO!
para seguir adiante no tutorial, crie uma aplicação django chamada "artigo"
Configuração de urls
O Django tem urls configuráveis. E isso quer dizer que eu posso definir praticamente qualquer combinação de "strings" e "barras" ("/") para acessar uma página do meu sistema.
Veja alguns exemlos abaixo
# arquivo: django_necto_fatec/django_intro_proj/djproj/djproj/urls.py
from django.urls import path
from . import views
urlpatterns = [
# include do arquivo de urls da aplicação "artigo"
path('artigos/', include('artigo.urls')),
# ... outros definições de padrões
path('admin/', admin.site.urls),
]
crie e edite o arquivo urls.py da aplicação "artigo"
# arquivo: django_necto_fatec/django_intro_proj/djproj/artigo/urls.py
from django.urls import path, re_path
from . import views
# as urls abaixo são inclusas no djproj/urls.py
# então a URL = "artigos/<url_definida_aqui>
urlpatterns = [
# ex.: http://127.0.0.1:8000/artigos/
# na view
path('', views.artigo_ultimos, name="artigos_ultimos"),
# ex.: http://127.0.0.1:8000/artigos/pagina/2/
# na view -> def page(request, num=1):
path('pagina/<int:pag>/', views.artigo_pagina, name="artigos_pagina"),
# ex.: http://127.0.0.1:8000/artigos/2022/
# envia o parametro ano, definido na regex
re_path(r'^(?P<ano>[0-9]{4})/$', views.artigo_ano, name="artigos_ano"),
]
Views
Exemplos de views
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.http import JsonResponse
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
def response_view(request):
''' view utilizando HttpResponse'''
# ...
t = loader.get_template('appdjango/nometemplate.html')
c = {'foo': 'bar'}
return HttpResponse(t.render(c, request), content_type='application/xhtml+xml')
def render_view(request):
''' view utilizando render (shortcut)'''
# ...
return render(
request, 'appdjango/nometemplate.html', {
'var': 'value',
},
content_type='application/xhtml+xml')
views para o tutorial
from django.shortcuts import render
from django.http import HttpResponse
def artigo_ultimos(request):
return HttpResponse('<h1>artigos ultimos</h1>')
def artigo_pagina(request, pag=1):
return HttpResponse('<h1>artigos pagina</h1>')
def artigo_ano(request, ano=2021):
return HttpResponse('<h1>artigo ano</h1>')
Template {{ variaveis}}, {% tags %} e filtros
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
Nota
- Links da documentação do Django sobre Templates:
Comentar sobre a linguagem de template do Django e JINJA e outras cossitas
Models
Models são classes que herdam da classe models.Model do framework Django.
ex.:
from django.db import models # importação da classe models do Django class Artigo(models.Model): titulo = models.CharField('Título', max_length=50) # campo "varchar" de até 50 caracteres texto = models.TextField('Corpo') # campo texto autor = models.ForeignKey(User, on_delete=models.CASCADE) # def Chave Estrangeira para o Modelo User data_criacao = models.DateTimeField('Criado em', auto_now_add=True) # def campo ""datetime" data_pub = models.DateTimeField('Publicado em')
Uma classe "modelo" é a representação Python de uma relação ("relation" ou tabela) no seu banco de dados.
- Isso quer dizer que a classe Python acima, que herda de models.Model,
- é a representação de uma tabela no banco de dados como a abaixo - o exemplo utiliza o o banco de dados SQLite.
CREATE TABLE "artigo_artigo" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "titulo" varchar(50) NOT NULL, "texto" text NOT NULL, "data_criacao" datetime NOT NULL, "data_pub" datetime NOT NULL, "autor_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED)
A classe "Artigo"
# titulo = models.CharField('Título', max_length=50)
Nota
adicionar comentario sobre relacionamento e regras normais. - django model fields page da doc
Make migrations e migrate
Cuidado facil nao quer dizer que deve ser usado sem cuidado
(django_intro_env) $> python manage.py makemigrations
# saida esperada .... ALGO COMO ! ...
Migrations for 'artigo':
artigo/migrations/0001_initial.py
- Create model Artigo
Django "migrations" são geradas nos diretórios "migrations" de cada aplicação Django.
O comando makemigrations somente gera os arquivos com o código Python para aplicar as alterações no banco de dados, mas não aplica as alterações !
Para aplicar as alterações é necessário um segundo comando o migrate
$> python manage.py migrate
(django_intro_env) $> python manage.py migrate
# ... o retorno é a lista de migrações executadas.
Operations to perform:
Apply all migrations: admin, artigo, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying artigo.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
$> python manage.py dbshell
sqlite> .tables
Django Admin site
- CUSTOMIZACAO É PERIGOSO
- se mal feita perde a capacidade de de atualizações.
python manage.py createsuperuser
Toda vez que vez que houver alteração de modelos
$> python manage.py makemigrations
$> python manage.py migrate
Para habilitar a interface de administracao par ao seu modelo , registre no "admin.py" mais póximo.
from django.contrib import admin from .models import Artigo
admin.site.register(Artigo)
https://docs.djangoproject.com/en/3.2/ref/contrib/admin/
- próximos tópicos:
- Django Forms
- Webserver wsgi
- Middlewares
- Para ler a Documentação do Django por conteúdo:
- https://docs.djangoproject.com/pt-br/3.2/contents/