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"

request/response image

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

O Django está instalado ?

$> pip list --local

ou

$> pip freeze

Dica

repare na saída dos 2 comandos

Iniciando um projeto Django

  1. Criar um diretório para o projeto - com o nome de django_intro_proj
  2. 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"

django site front page

tela inicial de um projeto Django quando não há urls definidas além das padrão.

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

django_http.png

Django esquema request/response --fonte: doc do django.

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

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.

https://www.djangoproject.com/

Alguns sites onde o Django é usado

Partes do Django

  1. URL Configuration

  2. Views

  3. Template

  4. Models

  5. Django Admin

  6. Django Settings

  7. Middlewares

  8. 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 %}

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/