// aula 2 · Python · Web com Django

Django — o framework
que vem com tudo


O que é Django e por que ele existe

"The web framework for perfectionists with deadlines"

Esse é o slogan oficial do Django — e ele resume muito bem o espírito do framework: feito para quem quer construir sistemas web sérios, com qualidade, sem perder tempo reinventando a roda. Django já vem com tudo que você precisa para uma aplicação web completa: sistema de banco de dados, autenticação de usuários, painel administrativo, sistema de templates, proteção contra os ataques mais comuns da web e muito mais.

Enquanto o Flask te dá uma caixa de ferramentas e diz "monta do seu jeito", o Django te entrega uma casa mobiliada e diz "pode morar — e personalizar o que precisar".

Um pouco de história

Django foi criado em 2003 por Adrian Holovaty e Simon Willison no jornal Lawrence Journal-World, no Kansas (EUA). Eles precisavam publicar notícias rápido, com prazo apertado — e criaram um framework que permitia isso. Em 2005 foi lançado como open source. O nome é uma homenagem ao guitarrista de jazz Django Reinhardt. Hoje é mantido pela Django Software Foundation e tem uma comunidade enorme no mundo inteiro.

Batteries included

"Baterias incluídas" é como a comunidade descreve o Django. ORM, admin, autenticação, formulários, segurança — tudo já está lá, configurado e funcionando.

Rápido para desenvolver

Você consegue criar um sistema com cadastro de usuários, banco de dados e painel admin em minutos — coisas que levariam dias construindo do zero.

Seguro por padrão

Django já protege contra SQL Injection, XSS, CSRF e clickjacking por padrão. Segurança não é algo que você adiciona depois — já está no framework.

Escalável de verdade

Instagram, Pinterest, Disqus e Mozilla usam ou usaram Django. O framework que começou num jornal pequeno hoje sustenta plataformas com bilhões de usuários.


A arquitetura MTV — como Django organiza tudo

Separando responsabilidades em três camadas

Django segue o padrão arquitetural MTV — Model, Template, View. É uma variação do famoso MVC (Model-View-Controller) que você encontra em muitos outros frameworks. A ideia central é sempre a mesma: separar os dados, a lógica e a apresentação. Cada parte tem uma responsabilidade bem definida e não deve invadir o espaço da outra.

M
Model
Define a estrutura dos dados e cuida de tudo que envolve o banco de dados. É a sua "verdade" — os dados do sistema.
T
Template
É o HTML da página — a camada de apresentação. Recebe os dados da View e os exibe para o usuário de forma visual.
V
View
É o cérebro. Recebe a requisição, conversa com o Model para buscar dados, e passa esses dados para o Template renderizar.

Como as três camadas conversam

Imagine um blog. A Model é a tabela Post no banco de dados — com campos de título, conteúdo, data e autor. A View é a função que recebe a requisição de "listar posts", vai ao banco buscar os posts e passa a lista para o template. O Template é o HTML que formata e exibe esses posts numa página bonita para o usuário.

O Django é o maestro que coordena esse fluxo — conectando URLs às Views, Views aos Models, e Models ao banco de dados.


Como Django funciona por dentro — o ciclo de uma requisição

1
Navegador envia a requisição O usuário acessa /blog/. O navegador manda uma requisição HTTP GET para o servidor Django.
2
Django consulta o URLconf O Django olha para o arquivo urls.py — uma tabela que mapeia URLs para Views. Achou a URL /blog/? Chama a View correspondente.
3
A View processa a requisição A View recebe o objeto request com tudo sobre a requisição. Ela decide o que fazer — normalmente busca dados no banco via Model.
4
Model busca os dados no banco O ORM do Django traduz a consulta Python para SQL e busca os dados no banco. Você nunca precisou escrever SQL — o Django fez por você.
5
Template renderiza o HTML A View passa os dados para o template. O sistema de templates do Django monta o HTML final com as variáveis preenchidas.
6
Resposta HTTP volta ao navegador O HTML pronto é embrulhado numa resposta HTTP e enviado de volta. O navegador exibe a página para o usuário.

Instalação e primeiro projeto

Terminal
# 1. Crie e ative o ambiente virtual
python -m venv venv
source venv/bin/activate    # Linux/Mac
venv\Scripts\activate       # Windows

# 2. Instale o Django
pip install django

# 3. Crie o projeto Django
django-admin startproject meublog .
# O ponto (.) cria na pasta atual — evita pasta duplicada

# 4. Rode o servidor de desenvolvimento
python manage.py runserver

Abra http://127.0.0.1:8000 no navegador

Você vai ver a página de boas-vindas do Django com um foguete — significa que está tudo funcionando! O manage.py é o canivete suíço do Django: com ele você cria apps, aplica migrações, cria superusuários e muito mais.

Estrutura do projeto criado

Estrutura gerada pelo django-admin
meublog/
├── manage.py              # comando principal do Django
└── meublog/               # pacote de configuração do projeto
    ├── __init__.py
    ├── settings.py        # todas as configurações do projeto
    ├── urls.py            # URLs raiz do projeto
    ├── asgi.py            # ponto de entrada para servidores async
    └── wsgi.py            # ponto de entrada para servidores tradicionais

O que é cada arquivo?

manage.py — você vai usar esse arquivo o tempo todo. python manage.py runserver, python manage.py migrate, python manage.py createsuperuser — tudo passa por ele.

settings.py — o coração das configurações. Banco de dados, apps instalados, idioma, fuso horário, chave secreta, arquivos estáticos — tudo aqui.

urls.py — a entrada de URLs do projeto. As URLs de cada app serão "incluídas" aqui.


Apps — a modularidade do Django

Um projeto Django é feito de Apps

No Django, um projeto é o todo — as configurações gerais, as URLs raiz, o banco de dados. Dentro do projeto, você cria apps — módulos independentes, cada um responsável por uma funcionalidade específica. Um app de blog, um app de autenticação, um app de comentários. Cada um pode até ser reutilizado em outros projetos.

Essa separação mantém o código organizado, cada app com sua própria pasta, seus próprios models, views e URLs.

Terminal — criando um app
python manage.py startapp posts

# Estrutura criada automaticamente:
posts/
├── __init__.py
├── admin.py       # registra models no painel admin
├── apps.py        # configuração do app
├── migrations/    # histórico de mudanças no banco
├── models.py      # define as tabelas do banco
├── tests.py       # testes automatizados
└── views.py       # lógica das requisições

Não esqueça de registrar o app no settings.py

Depois de criar um app, você precisa adicioná-lo à lista INSTALLED_APPS no settings.py. Sem isso, o Django não reconhece o app e nada funciona.

meublog/settings.py — registrando o app
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "posts",   # ← seu app aqui
]

Models e ORM — banco de dados sem escrever SQL

O que é um Model?

Um Model é uma classe Python que representa uma tabela no banco de dados. Cada atributo da classe vira uma coluna da tabela. Você escreve Python — o Django cria e gerencia o SQL por você. Isso é o ORM do Django em ação.

E não é só criar tabelas: com o ORM você faz consultas, filtros, ordenações, joins — tudo em Python, sem nunca tocar em SQL diretamente.

posts/models.py
from django.db import models

class Post(models.Model):
    titulo     = models.CharField(max_length=200)          # texto curto
    conteudo   = models.TextField()                         # texto longo
    publicado  = models.BooleanField(default=False)        # verdadeiro/falso
    criado_em  = models.DateTimeField(auto_now_add=True)   # data automática ao criar
    atualizado = models.DateTimeField(auto_now=True)       # data automática ao salvar

    class Meta:
        ordering = ["-criado_em"]   # mais recentes primeiro por padrão

    def __str__(self):
        return self.titulo          # como o objeto aparece no admin e no shell

Criando as tabelas no banco — Migrations

O que são Migrations?

Migrations são o sistema que o Django usa para manter o banco de dados em sincronia com seus Models. Toda vez que você cria ou altera um Model, gera uma migration — um arquivo Python que descreve o que mudou. Depois você aplica essa migration ao banco. É como um histórico versionado do seu banco de dados.

Terminal — migrations
# 1. Gera o arquivo de migration baseado nos seus Models
python manage.py makemigrations

# 2. Aplica as migrations ao banco de dados
python manage.py migrate

# Sempre nessa ordem: makemigrations → migrate

Consultando dados com o ORM

Python — ORM em ação
from posts.models import Post

# CREATE — criando um post
post = Post.objects.create(titulo="Meu primeiro post", conteudo="Olá!")

# READ — buscando todos os posts
todos = Post.objects.all()

# READ — filtrando publicados, ordenados por data
publicados = Post.objects.filter(publicado=True).order_by("-criado_em")

# READ — buscando um post pelo ID (lança exceção se não encontrar)
post = Post.objects.get(id=1)

# UPDATE — atualizando um campo
post.titulo = "Título atualizado"
post.save()

# DELETE — excluindo
post.delete()

# PESQUISA — título contendo "Django" (case-insensitive)
resultados = Post.objects.filter(titulo__icontains="django")
Tipo de campoUso
CharField(max_length=n)Texto curto — nome, título, slug
TextField()Texto longo — conteúdo, descrição
IntegerField()Número inteiro
FloatField()Número decimal
BooleanField()Verdadeiro ou falso
DateTimeField()Data e hora
EmailField()E-mail — valida o formato automaticamente
ImageField()Imagem — salva o arquivo e guarda o caminho
ForeignKey(Model, ...)Relacionamento muitos-para-um
ManyToManyField(Model)Relacionamento muitos-para-muitos

Views — processando as requisições

A View é o cérebro da operação

Uma View no Django é uma função (ou classe) Python que recebe uma requisição HTTP e retorna uma resposta HTTP. É nela que toda a lógica acontece: buscar dados, validar formulários, chamar serviços externos, decidir qual template renderizar.

posts/views.py — views baseadas em função
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post

# Lista todos os posts publicados
def lista_posts(request):
    posts = Post.objects.filter(publicado=True)
    # render() = shortcut para render_template() do Django
    return render(request, "posts/lista.html", {"posts": posts})

# Detalhe de um post específico
def detalhe_post(request, pk):
    # get_object_or_404 busca pelo ID e retorna 404 se não existir
    post = get_object_or_404(Post, pk=pk, publicado=True)
    return render(request, "posts/detalhe.html", {"post": post})

# Criar um novo post via formulário
def criar_post(request):
    if request.method == "POST":
        titulo   = request.POST.get("titulo")
        conteudo = request.POST.get("conteudo")
        Post.objects.create(titulo=titulo, conteudo=conteudo, publicado=True)
        return redirect("lista_posts")   # redireciona pelo nome da URL
    return render(request, "posts/form.html")

Templates Django

Igual ao Jinja2, mas com algumas diferenças

O sistema de templates do Django é muito parecido com o Jinja2 do Flask — herança de templates, variáveis com {{ }}, blocos de lógica com {% %}. A principal diferença é que as tags de template do Django têm algumas restrições por segurança — por exemplo, você não pode chamar qualquer função Python dentro dos templates.

Estrutura de templates no app
posts/
└── templates/
    └── posts/        # pasta com o nome do app (convenção Django)
        ├── lista.html
        ├── detalhe.html
        └── form.html
posts/templates/posts/lista.html
{% extends "base.html" %}

{% block titulo %}Posts{% endblock %}

{% block conteudo %}
  <h1>Todos os Posts</h1>

  {% for post in posts %}
    <article>
      <h2><a href="{% url 'detalhe_post' post.pk %}">{{ post.titulo }}</a></h2>
      <p>{{ post.criado_em|date:"d/m/Y" }}</p>
      <p>{{ post.conteudo|truncatewords:30 }}</p>
    </article>
  {% empty %}
    <p>Nenhum post ainda.</p>
  {% endfor %}
{% endblock %}
Filtro DjangoO que fazExemplo
date:"d/m/Y"Formata data{{ data|date:"d/m/Y" }}
truncatewords:nCorta após n palavras{{ texto|truncatewords:20 }}
upperMaiúsculas{{ nome|upper }}
lowerMinúsculas{{ nome|lower }}
lengthTamanho de lista ou string{{ lista|length }}
default:"texto"Valor se variável for vazia{{ nome|default:"Anônimo" }}
safeRenderiza HTML sem escapar{{ conteudo|safe }}

URLs — conectando tudo

URLconf — a tabela de rotas do Django

O Django usa um sistema de URLs declarativo. Você cria um arquivo urls.py em cada app com as rotas daquele app, e depois inclui esse arquivo no urls.py principal do projeto. Assim cada app gerencia suas próprias URLs — tudo modular e organizado.

posts/urls.py — URLs do app
from django.urls import path
from . import views

# app_name permite usar namespace nas URLs: {% url 'posts:lista' %}
app_name = "posts"

urlpatterns = [
    path("",           views.lista_posts,  name="lista_posts"),
    path("<int:pk>/",  views.detalhe_post, name="detalhe_post"),
    path("novo/",       views.criar_post,   name="criar_post"),
]
meublog/urls.py — URLs raiz do projeto
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    # inclui todas as URLs do app posts no prefixo /posts/
    path("posts/", include("posts.urls")),
]

✅ Sempre nomeie suas URLs

Com o parâmetro name, você pode referenciar uma URL pelo nome em vez de escrever o caminho fixo. Assim, se a URL mudar, você só muda em um lugar. No template use {"% url 'lista_posts' %"}; na view use redirect('lista_posts').


Admin — o painel que vem de graça

Um painel de administração completo sem escrever nada

Essa é uma das funcionalidades mais impressionantes do Django. Com pouquíssimas linhas de código, você ganha um painel administrativo completo — interface para criar, editar, excluir e pesquisar registros de qualquer Model do seu sistema. É algo que em outros frameworks levaria dias de trabalho.

Terminal — criando o superusuário
python manage.py createsuperuser
# Vai pedir: username, email, password
posts/admin.py — registrando no admin
from django.contrib import admin
from .models import Post

# Versão básica — apenas registra o Model
admin.site.register(Post)

# Versão personalizada — controla como aparece no admin
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display   = ["titulo", "publicado", "criado_em"]  # colunas na lista
    list_filter    = ["publicado"]                          # filtros na lateral
    search_fields  = ["titulo", "conteudo"]                 # campo de busca
    list_editable  = ["publicado"]                          # edita inline na lista

Acesse http://127.0.0.1:8000/admin

Login com o superusuário que você criou. Você vai ver o painel completo com seus Models listados, podendo criar e editar posts direto pela interface — sem escrever nenhum HTML de formulário.


Mini projeto — Blog simples

O que vamos construir

Um blog funcional com listagem e detalhe de posts, criação via formulário e painel admin completo. Tudo isso com Django do zero.

1
Estrutura final do projeto
Estrutura
meublog/
├── manage.py
├── meublog/
│   ├── settings.py
│   └── urls.py
└── posts/
    ├── admin.py
    ├── models.py
    ├── views.py
    ├── urls.py
    └── templates/
        └── posts/
            ├── lista.html
            ├── detalhe.html
            └── form.html
2
posts/models.py
models.py
from django.db import models

class Post(models.Model):
    titulo    = models.CharField(max_length=200)
    conteudo  = models.TextField()
    publicado = models.BooleanField(default=True)
    criado_em = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-criado_em"]

    def __str__(self):
        return self.titulo
3
posts/views.py
views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post

def lista_posts(request):
    posts = Post.objects.filter(publicado=True)
    return render(request, "posts/lista.html", {"posts": posts})

def detalhe_post(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, "posts/detalhe.html", {"post": post})

def criar_post(request):
    if request.method == "POST":
        titulo   = request.POST.get("titulo", "").strip()
        conteudo = request.POST.get("conteudo", "").strip()
        if titulo and conteudo:
            Post.objects.create(titulo=titulo, conteudo=conteudo)
            return redirect("posts:lista_posts")
    return render(request, "posts/form.html")
4
posts/templates/posts/lista.html
lista.html
<!DOCTYPE html>
<html lang="pt-BR">
<head><title>Blog</title></head>
<body>
  <h1>📝 Blog</h1>
  <a href="{% url 'posts:criar_post' %}">+ Novo Post</a>

  {% for post in posts %}
    <article>
      <h2><a href="{% url 'posts:detalhe_post' post.pk %}">{{ post.titulo }}</a></h2>
      <small>{{ post.criado_em|date:"d/m/Y H:i" }}</small>
      <p>{{ post.conteudo|truncatewords:25 }}</p>
    </article>
    <hr>
  {% empty %}
    <p>Nenhum post publicado ainda.</p>
  {% endfor %}
</body>
</html>
5
Aplicar migrations e rodar
Terminal — finalizando
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver

# Acesse:
# http://127.0.0.1:8000/posts/       → lista de posts
# http://127.0.0.1:8000/posts/novo/  → criar post
# http://127.0.0.1:8000/admin/       → painel admin