// aula 2 · Python · Web com Django
O que é Django e por que ele existe
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".
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.
"Baterias incluídas" é como a comunidade descreve o Django. ORM, admin, autenticação, formulários, segurança — tudo já está lá, configurado e funcionando.
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.
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.
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
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.
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
/blog/. O navegador manda uma requisição HTTP GET para o servidor Django.
urls.py — uma tabela que mapeia URLs para Views. Achou a URL /blog/? Chama a View correspondente.
request com tudo sobre a requisição. Ela decide o que fazer — normalmente busca dados no banco via Model.
Instalação e primeiro projeto
# 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
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
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
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
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.
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
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.
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
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.
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
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.
# 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
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 campo | Uso |
|---|---|
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
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.
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
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.
posts/
└── templates/
└── posts/ # pasta com o nome do app (convenção Django)
├── lista.html
├── detalhe.html
└── form.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 Django | O que faz | Exemplo |
|---|---|---|
date:"d/m/Y" | Formata data | {{ data|date:"d/m/Y" }} |
truncatewords:n | Corta após n palavras | {{ texto|truncatewords:20 }} |
upper | Maiúsculas | {{ nome|upper }} |
lower | Minúsculas | {{ nome|lower }} |
length | Tamanho de lista ou string | {{ lista|length }} |
default:"texto" | Valor se variável for vazia | {{ nome|default:"Anônimo" }} |
safe | Renderiza HTML sem escapar | {{ conteudo|safe }} |
URLs — conectando tudo
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.
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"), ]
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")), ]
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
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.
python manage.py createsuperuser
# Vai pedir: username, email, password
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
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
Um blog funcional com listagem e detalhe de posts, criação via formulário e painel admin completo. Tudo isso com Django do zero.
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
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
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")
<!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>
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