Desenvolvimento Web com Django
Regis do Python
slides.com/regissantos/desenvolvimento-web-com-django
Criando uma página simples
cat << EOF > index.html
<h1 style="font-size: 180px;">Minha landpage</h1>
EOF
python -m http.server
Frameworks de CSS
- Bootstrap
- TailwindCSS
- Bulma
- PicoCSS
Uma página com framework de CSS
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<link rel="shortcut icon" href="https://www.djangoproject.com/favicon.ico">
<title>Landpage</title>
<!-- PicoCSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css" />
</head>
<body>
<h1 style="font-size: 180px;">Minha landpage</h1>
</body>
</html>
Banco de dados
SQLite
import sqlite3
# Conectar ao banco
conexao = sqlite3.connect('loja.db')
# Criar um cursor para executar comandos SQL
cursor = conexao.cursor()
# Criar tabela de produtos
cursor.execute('''
CREATE TABLE IF NOT EXISTS produtos (
id INTEGER PRIMARY KEY,
titulo TEXT NOT NULL,
preco REAL NOT NULL
)
''')
... continuação
# Inserir alguns produtos
produtos = [
("Notebook", 2500.99),
("Mouse wireless", 32.90),
("Monitor 24 pol", 650.00)
]
cursor.executemany(
"INSERT INTO produtos (titulo, preco) VALUES (?, ?)", produtos
)
... continuação
# Buscar todos os produtos
cursor.execute("SELECT * FROM produtos")
resultados = cursor.fetchall()
print("Produtos cadastrados:")
for produto in resultados:
print(f"ID: {produto[0]} | Título: {produto[1]} | Preço: R$ {produto[2]:.2f}")
# Confirmar as alterações e fechar conexão
conexao.commit()
conexao.close()
PostgreSQL
pip install psycopg2-binary
import psycopg2
try:
# Conectar ao banco PostgreSQL
conexao = psycopg2.connect(
host="localhost",
database="loja",
user="meu_usuario",
password="minha_senha",
port="5432"
)
# resto é igual...
except psycopg2.Error as e:
print(f"Erro ao conectar ao PostgreSQL: {e}")
finally:
if conexao:
cursor.close()
conexao.close()
MySQL
import mysql.connector
try:
# Conectar ao banco MySQL
conexao = mysql.connector.connect(
host="localhost",
database="loja",
user="meu_usuario",
password="minha_senha",
port="3306"
)
cursor = conexao.cursor()
# ...
except mysql.connector.Error as e:
print(f"Erro ao conectar ao MySQL: {e}")
finally:
if conexao:
cursor.close()
conexao.close()
Diferenças
-
Biblioteca:
mysql.connectorao invés depsycopg2 - Porta padrão: 3306 (MySQL) vs 5432 (PostgreSQL)
-
Exceção:
mysql.connector.Errorvspsycopg2.Error
Criando o projeto
django-admin startproject apps .
cd apps/
python manage.py startapp core
python ../manage.py startapp core
python ../manage.py startapp produto
cd ..
Settings
from pathlib import Path
from decouple import config
SECRET_KEY = config('SECRET_KEY')
INSTALLED_APPS = [
# ...
'django_extensions',
'apps.core',
'apps.produto',
]
Conexão com banco de dados
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('POSTGRES_DB', 'dicas_de_django_db'),
'USER': config('POSTGRES_USER', 'postgres'),
'PASSWORD': config('POSTGRES_PASSWORD', 'postgres'),
'HOST': config('DB_HOST', 'localhost'),
'PORT': config('DB_PORT', 5432, cast=int),
}
}
Um pequeno ajuste
# apps/core/apps.py
from django.apps import AppConfig
class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.core' # <---
# apps/produto/apps.py
from django.apps import AppConfig
class ProdutoConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.produto' # <---
Migrações
python manage.py migrate
Operations to perform:
Apply all migrations: admin, 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 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
Criando um super usuário
python manage.py createsuperuser
Usuário (leave blank to use 'regis'): admin
Endereço de email:
Password:
Password (again):
ORM
python manage.py shell
python manage.py shell_plus # django_extensions
>>> users = User.objects.all()
>>> users
<QuerySet [<User: admin>]>
>>> for user in users:
... print(user.id, user.username, user.password)
...
1 admin pbkdf2_sha256$1000000$yaXKSdSTV6Yjsyewdr7v3f$rfjNshlqwgxSvXJ3cgwaJMNAeLj1AgsJyjW3EEr93wQ=
>>>
Trocando a senha
>>> user = User.objects.get(username='admin')
>>> user
<User: admin>
>>> user.set_password('teste')
>>> user.save()
>>> user.password
'pbkdf2_sha256$1000000$ybu4NGoCe1MMutgAGr7oSW$NBlsqR3ICe+unfW1OSgMbHQ82MWCpsnKPhUrMoY3968='
Criando um modelo
# produto/models.py
from django.db import models
class Produto(models.Model):
titulo = models.CharField('título', max_length=100)
descricao = models.TextField(
'descrição',
null=True,
blank=True
)
sku = models.CharField(max_length=8, unique=True)
preco = models.DecimalField(
'preço',
max_digits=9,
decimal_places=2
)
class Meta:
ordering = ('titulo',)
verbose_name = 'produto'
verbose_name_plural = 'produtos'
def __str__(self):
return f'{self.sku} - {self.titulo}'
Rodando as migrações
(.venv):/live$ python manage.py makemigrations # <--
Migrations for 'produto':
apps/produto/migrations/0001_initial.py
+ Create model Produto
(.venv):/live$ python manage.py migrate # <--
Operations to perform:
Apply all migrations: admin, auth, contenttypes, produto, sessions
Running migrations:
No migrations to apply.
Painel de Admin
# produto/admin.py
from django.contrib import admin
from .models import Produto
@admin.register(Produto)
class ProdutoAdmin(admin.ModelAdmin):
list_display = ('titulo', 'sku', 'preco')
search_fields = ('sku', 'titulo', 'descricao')
Criando views
# core/views.py
from django.shortcuts import render
def index(request):
template_name = 'index.html'
return render(request, template_name)
# produto/views.py
from django.shortcuts import render
from .models import Produto
def produto_list(request):
template_name = 'produto/produto_list.html'
object_list = Produto.objects.all()
context = {'object_list': object_list}
return render(request, template_name, context)
Criando urls
# core/urls.py
from django.urls import path
from apps.core import views as v
app_name = 'core'
urlpatterns = [
path('', v.index, name='index'),
]
# produto/urls.py
from django.urls import path
from apps.produto import views as v
app_name = 'produto'
urlpatterns = [
path('', v.produto_list, name='produto_list'),
]
# urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('', include('apps.core.urls', namespace='core')),
path('produto/', include('apps.produto.urls', namespace='produto')),
path('admin/', admin.site.urls),
]
Criando um template
<!-- base.html -->
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<link rel="shortcut icon" href="https://www.djangoproject.com/favicon.ico">
<title>Landpage</title>
<!-- PicoCSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css" />
</head>
<body class="container-fluid">
{% include "includes/menu.html" %}
{% block content %}{% endblock content %}
</body>
</html>
<!-- menu.html -->
<ul>
<li>
<a href="{% url 'produto:produto_list' %}">Produtos</a>
</li>
</ul>
<!-- index.html -->
{% extends "base.html" %}
{% block content %}
<h1>Minha landpage</h1>
{% endblock content %}
<!-- produto_list.html -->
{% extends "base.html" %}
{% block content %}
<h1>Produtos</h1>
<table>
<thead>
<tr>
<th>Título</th>
<th>SKU</th>
<th>Preço</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<td>{{ object.titulo }}</td>
<td>{{ object.sku }}</td>
<td>{{ object.preco }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
MTV


Sites
djangoproject.com
django-ninja.dev
django-rest-framework.org
dicas-de-django.com.br
Livros
Django 3 by Example
Antonio Melé

Django Admin Cookbook
books.agiliq.com/projects/django-admin-cookbook/en/latest/

Two Scoops of Django 3.x

Atualmente: Django 5.2.3
Django Ninja


Meu Canal
Regis do Python

Desenvolvimento Web com Django
By Regis Santos
Desenvolvimento Web com Django
- 44