Workshop | Desenvolvimento de Back-end Django | Parte 2

Agostinho Pina Ramos
14 min readFeb 20, 2022

No seguimento do artigo anterior (parte 1), vamos criar o nosso primeiro projeto em Django 😊.

Neste tutorial, construiremos uma aplicação Blog com Django que permite aos utilizadores criar, editar e excluir postagens. A página inicial listará todas as postagens do blog e haverá uma página de detalhes dedicada para cada postagem individual. O Django consegue fazer coisas mais avançadas, mas fazer um blog é um excelente primeiro passo para ter uma boa compreensão do framework. O propósito deste capítulo é ter uma ideia geral sobre o funcionamento do Django.

Aqui está uma prévia do que vamos fazer.

Django — welcome page

Pré-requisitos

Antes de começar, deve ter um utilizador não-root com privilégios sudo disponíveis no seu servidor Ubuntu 20.04.

  • Python
  • PIP

Instalação Global dos Pacotes

Se deseja instalar o Django utilizando um repositório do Ubuntu, o processo é muito simples.

Primeiramente, atualize o seu índice de pacotes local com o apt:

sudo apt update

Em seguida, verifique qual a versão do Python já existente na sua máquina, pode verificar, digitando o seguinte comando:

python3 -V

Se não tiver o Python instalado, veja aqui como instalar.

Em seguida, instale o Django:

python3 -m pip install Django

Após terminar a instalação, pode verificar se a instalação foi bem-sucedida executando o seguinte comando:

django-admin --version

Isso significa que o software foi instalado com sucesso.

O próximo passo, selecionaremos o ambiente de trabalho. No meu caso será o seguinte diretório:

cd /var/opt

Agora para ter permissão de escrita no diretório opt deve executar o seguinte comando:

sudo chown $USER:$USER .

Agora execute o seguinte comando para criar um projeto Django.

django-admin startproject mysite

Isso gerará uma estrutura de projetos com vários diretórios e scripts Python.

├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
├── manage.py

Em seguida, precisamos criar uma aplicação Django chamada blog. A aplicação server apenas para executar uma tarefa específica. Para isso executaremos o seguinte comando:

cd mysitepython3 manage.py startapp blog

O comando criará uma aplicação chamada blog no nosso projeto.

├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
├── manage.py
└── blog
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py

Agora precisamos informar o Django que uma nova aplicação foi criada, abra o ficheiro que se segue mysite/settings.py

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

Agora adicione o blog da aplicação criada recentemente e salve-o.

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog'
]

Em seguida, a partir do diretório mysite, execute o seguinte comando:

python3 manage.py makemigrations
Django with Visual Studio Code
├── db.sqlite3
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
├── manage.py
└── blog
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py

Como já deve ter percebido, o ficheiro db.sqlite3 foi gerado automaticamente.

A seguir execute o seguinte comando:

python3 manage.py migrate
Django migrate

Acabamos de aplicar todas as migrações não aplicadas na base de dados SQLite.

Agora testaremos as nossas configurações executando o servidor de desenvolvimento interno do Django.

python3 manage.py runserver

Como pode ver já conseguimos ver a nossa aplicação disponível no seguinte endereço http://127.0.0.1:8000/

Abra o seu navegador e introduza o endereço acima, se tudo correu bem, deve ver a seguinte página.

Django worked successfully

Modelo de base de dados

Agora definiremos os modelos de dados para o nosso blog. Um modelo é uma classe Python que cria subclasses django.db.models.Model, em que cada atributo representa um campo de base de dados. Usando esta funcionalidade de subclasse, automaticamente temos acesso a tudo dentro do django.db.models.Model e podemos adicionar campos e métodos adicionais conforme desejado. Teremos um modelo Post na nossa base de dados para armazenar os posts.

No ficheiro /var/opt/mysite/blog/models.py adicionaremos o seguinte código:

Django — Create your models here

Deve substituir pelo código que se segue:

Ficheiro: blog/models.py

from django.db import models
from django.contrib.auth.models import User
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title

Na parte superior, estamos importando a classe models e, em seguida, criando uma subclasse de models.Model como qualquer blog típico, cada postagem do blog terá um título, slug, nome do autor e o carimbo de data/hora ou data em que o artigo foi publicado ou atualizado pela última vez.

Show Post model

Observe como declaramos uma tupla para STATUS uma postagem para manter as postagens de rascunho e publicadas separadas quando as renderizamos com modelos.

A classe Meta no modelo contém metadados. Dizemos ao Django para classificar os resultados no created_on campo em ordem decrescente por padrão quando consultamos o banco de dados. Especificamos a ordem decrescente usando o prefixo negativo. Ao fazer isso, as postagens publicadas recentemente aparecerão primeiro.

O __str__() método é a representação padrão legível por humanos do objeto. O Django irá usá-lo em muitos lugares, como no site de administração.

Agora que o nosso novo modelo de base de dados foi criado, precisamos criar um registo de migração e migrar a alteração para nossa base de dados.

Para isto, devemos fazer no nosso terminal CTRL+C para terminar a execução do servidor, e a seguir, podemos executar o seguinte comando:

python3 manage.py makemigrations
python3 manage.py migrate

Se tudo correu bem, veremos a seguinte tela:

Criando um site de Administração

Vamos criar um painel de administração para criar e gerenciar Posts. Felizmente, o Django vem com uma interface de administração embutida para tais tarefas.

Para usar o administrador do Django primeiro, precisamos criar um super-utilizador executando o seguinte comando:

python3 manage.py createsuperuser

Será solicitado o username, email e password. Atenção que não deve esquecer da senha, a mesma deve ter pelo menos 8 dígitos e apenas o administrador deve ter acesso a esta informação.

Django — Create superuser

Depois disso, execute novamente o servidor de desenvolvimento e vá para o endereço http://127.0.0.1:8000/admin/

python3 manage.py runserver

Agora de ver a página de Django administration, digite os detalhes como username e password que introduziu no momento de criação do super-utilizador:

Depois de fazer o login, deverá ver um painel de administração básico com modelos de Grupos e Utilizadores que vêm da estrutura de autenticação do Django localizada em django.contrib.auth.

Painel — Django administration

Ainda assim, não podemos criar posts a partir do painel que precisamos para adicionar o modelo Post ao nosso admin.

Adicionando modelos ao site de administração

Abra o seguinte ficheiro blog/admin.py e registe o modelo Post lá da seguinte forma:

Ficheiro: blog/admin.py

from django.contrib import admin
from .models import Post
admin.site.register(Post)

Depois de atualizar a página, já conseguimos ver o nosso modelo Post.

Django — Administration with Post

Agora vamos criar nosso primeiro post no blog, clique no ícone Adicionar ao lado de Post que o levará a outra página onde se pode criar um Post. Preencha os respetivos formulários e crie seu primeiro Post.

My first post

Assim que terminar de salvar a publicação, será redirecionado para a página da lista de postagens com uma mensagem de sucesso na parte superior.

Embora funcione, podemos personalizar a forma como os dados são exibidos no painel de administração conforme a nossa conveniência. Abra o blog/admin.py e substitua-o pelo código abaixo.

Ficheiro: blog/admin.py

from django.contrib import admin
from .models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'status','created_on')
list_filter = ("status",)
search_fields = ['title', 'content']
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Post, PostAdmin)

Isso tornará o nosso painel de administração mais eficiente. Agora, se precisar visitar a lista de publicações, verá mais detalhes sobre a postagem.

Django post with more details

O atributo list_display faz o que o seu nome sugere, exibir as propriedades mencionadas na tupla na lista de postagens de cada postagem.

Se notar mesmo à direita, há um filtro que está filtrado a postagem dependendo do seu status, isso é feito pelo método list_filte.

Agora temos uma barra de pesquisa no topo da lista que irá pesquisar a base de dados a partir dos atributos search_fields. O último atributo prepopulated_fields preenche o slug, agora se cria um post o slug será preenchido automaticamente com base no seu título.

Agora que o nosso modelo de base de dados está completo, precisamos criar as visualizações, URLs e modelos necessários para podermos exibir as informações na nossa aplicação.

Construindo as Views

Uma view do Django é apenas uma função Python que percebe uma requisição web e retorna uma resposta web. Vamos criar uma visualização baseada nas classes e mapear URLs para cada visualização e criar um modelo HTML para os dados retornados das visualizações.

Para isso deve abrir o seguinte arquivo blog/views.py e inserir o seguinte código:

Ficheiro: blog/views.py

from django.views import generic
from .models import Post
class PostList(generic.ListView):
queryset = Post.objects.filter(status=1).order_by('-created_on')
template_name = 'index.html'
class PostDetail(generic.DetailView):
model = Post
template_name = 'post_detail.html'

O ListViews embutido que é uma subclasse de visões genéricas baseadas em classe renderiza uma lista com os objetos do modelo específico, precisamos apenas mencionar o modelo, da mesma forma DetailView fornece uma visão detalhada para um determinado objeto do modelo fornecido.

Observe que para a view PostList aplicamos um filtro para que apenas o post com estatus publicado seja exibido no front end do nosso blog. Também da mesma consulta, organizamos todos os posts por data de criação. O sinal (-) antes do created_on o que significa que a última postagem estaria no topo e assim por diante.

Adicionar padrões de URL para a View

Precisamos mapear a URL para as visualizações que fizemos acima. Quando um utilizador faz uma solicitação para uma página na sua aplicação Web, o controlador Django assume o controlo para procurar a visualização correspondente por meio do ficheiro urls.py e, em seguida retorna a resposta HTML ou um erro 404 (não encontrado), caso não encontre o ficheiro.

Agora, crie um ficheiro blog/urls.py com o código que se segue:

Ficheiro: blog/urls.py

from . import views
from django.urls import path
urlpatterns = [
path('', views.PostList.as_view(), name='home'),
path('<slug:slug>/', views.PostDetail.as_view(), name='post_detail'),
]

Mapeamos padrões gerais de URL para nossas visualizações usando a função path. O primeiro padrão pega uma string vazia denotada por ‘ ’ e retorna o resultado gerado a partir da view PostList que é essencialmente uma lista de postagens para nossa página inicial e por último temos um nome de parâmetro opcional que é basicamente um nome para a view que será usada posteriormente nos modelos.

Os nomes são um parâmetro opcional, mas é uma boa prática dar nomes únicos e memoráveis às visualizações, o que facilita nosso trabalho ao projetar modelos, ajuda a manter as coisas organizadas à medida que a quantidade de URLs aumenta.

Em seguida, temos a expressão generalizada para a view PostDetail que resolvem o slug (uma string que consiste em letras ou números ASCII). O Django usa colchetes angulares < > para captar os valores da URL e retornar a página de detalhes do post equivalente.

Agora precisamos incluir essas URLs de blog no projeto real para abrir o ficheiro mysite/urls.py.

Ficheiro: mysite/urls.py

from django.contrib import adminurlpatterns = [
path('admin/', admin.site.urls),
]

Importe agora a função include e, em seguida, adicione o caminho para o novo ficheiro mysite/urls.py na lista de padrões de URL

Ficheiro: mysite/urls.py

from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]

Agora, toda a solicitação será tratada diretamente pela aplicação do blog.

Criando modelos para as views

Terminamos os Modelos e Views, agora precisamos fazer templates para renderizar o resultado para os nossos utilizadores. Para usar os templates do Django, precisamos primeiro definir uma configuração do template.

Crie modelos de diretórios base. Agora abra o ficheiro mysite/settings.py do projeto logo abaixo BASE_DIR adicione a rota ao diretório do template da seguinte forma.

Ficheiro: mysite/settings.py

import os
from pathlib import Path
TEMPLATES_DIRS = os.path.join(BASE_DIR,'templates')
Django — Add template dir

Já no ficheiro mysite/settings.py, vá até o, TEMPLATES e adicione o recém-criado TEMPLATE_DIRS no ficheiro DIRS, no final deve ficar da seguinte forma:

Ficheiro: mysite/settings.py

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [TEMPLATES_DIRS],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

Agora salve e feche o ficheiro que terminamos com as configurações.

O Django torna possível separa Python e HTML, o Python vai em views e o HTML vai em templates. O Django possui uma linguagem de template poderosa que permite especificar com os dados que são exibidos. Ele é vaseado em tags de modelo, variáveis de modelo e filtros de modelo.

Vamos começar com uma base de um ficheiro HTML chamada base.html e outro chamada index.html. Então mais tarde, quando adicionarmos modelos para a página inicial e as páginas de detalhes da postagem, os mesmo podem herdar de base.html.

Vamos começar com o ficheiro base.html que terá elementos comuns para o blog em qualquer página como a barra de navegação e o rodapé. Além disso, estamos usando o Bootstrap para a fonte UI e Roboto.

Ficheiro: templates/base.html

<!DOCTYPE html>
<html>
<head>
<title>Workshop - Mestrado em Computação Móvel</title>
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700" rel="stylesheet">
<meta name="google" content="notranslate" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous" />
</head>
<body>
<style>
body {
font-family: "Roboto", sans-serif;
font-size: 17px;
background-color: #fdfdfd;
}
.shadow {
box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.1);
}
.btn-danger {
color: #fff;
background-color: #f00000;
border-color: #dc281e;
}
.masthead {
background: #3398E1;
height: auto;
padding-bottom: 15px;
box-shadow: 0 16px 48px #E3E7EB;
padding-top: 10px;
}
</style>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-light shadow" id="mainNav">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'home' %}">Workshop - Mestrado em Computação Móvel</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive"
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item text-black">
<a class="nav-link text-black font-weight-bold" href="#">About</a>
</li>
<li class="nav-item text-black">
<a class="nav-link text-black font-weight-bold" href="#">Policy</a>
</li>
<li class="nav-item text-black">
<a class="nav-link text-black font-weight-bold" href="#">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}
<!-- Content Goes here -->
{% endblock content %}
<!-- Footer -->
<footer class="py-3 bg-grey">
<p class="m-0 text-dark text-center ">Copyright &copy; Agostinho Ramos</p>
</footer>
</body>
</html>

Este é um ficheiro HTML normal, exceto pelas tags dentro de chaves { }, que são chamadas de tags de modelo.

O {% url ‘home’ %} Retorna uma referência de caminho absoluto, gerando um link para visualização inicial que também é a visualização de lista para postagens.

O {% block content %} define um bloco que pode ser substituído por templates filhos, é aqui que o conteúdo do outro arquivo HTML será injetado.

Em seguida, faremos um pequeno widget de barra lateral que será herdado por todas as páginas do site. Observe que a barra lateral está sendo injetado no ficheiro templates/base.html, o que o torna disponível globalmente para páginas que herdam o ficheiro base.

Ficheiro: templates/sidebar.html

{% block sidebar %}<style>
.card{
box-shadow: 0 16px 48px #E3E7EB;
}
</style><!-- Sidebar Widgets Column -->
<div class="col-md-4 float-right ">
<div class="card my-4">
<h5 class="card-header">About Us</h5>
<div class="card-body">
<p class="card-text"> This awesome blog is made on the top of our Favourite full stack Framework 'Django', follow up the tutorial to learn how we made it..!</p>
<a href="https://djangocentral.com/building-a-blog-application-with-django"
class="btn btn-danger">Know more!</a>
</div>
</div>
</div>
{% endblock sidebar %}

Em seguida, crie o ficheiro templates/index.html do nosso blog que é uma página inicial.

Ficheiro: templates/index.html

{% extends "base.html" %}
{% block content %}
<style>
body {
font-family: "Roboto", sans-serif;
font-size: 18px;
background-color: #fdfdfd;
}
.head_text {
color: white;
}
.card {
box-shadow: 0 16px 48px #E3E7EB;
}
</style>
<header class="masthead">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class=" col-md-8 col-md-10 mx-auto">
<div class="site-heading">
<h3 class=" site-heading my-4 mt-3 text-white"> Welcome to my awesome Blog </h3>
<p class="text-light">We Love Django As much as you do..! &nbsp
</p>
</div>
</div>
</div>
</div>
</header>
<div class="container">
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8 mt-3 left">
{% for post in post_list %}
<div class="card mb-4">
<div class="card-body">
<h2 class="card-title">{{ post.title }}</h2>
<p class="card-text text-muted h6">{{ post.author }} | {{ post.created_on}} </p>
<p class="card-text">{{post.content|slice:":200" }}</p>
<a href="{% url 'post_detail' post.slug %}" class="btn btn-primary">Read More &rarr;</a>
</div>
</div>
{% endfor %}
</div>
{% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}
</div>
</div>
{%endblock%}

Com a tag {% extends %} template, dizemos ao Django para herdar do template base.html. Em seguida, estamos preenchendo os blocos do modelo base com conteúdo.

Observe que estamos usando o ciclo for em HTML que é o poder dos templates do Django que torna o HTML dinâmico. O loop está iterando pelas postagens e exibindo seu título, data, autor e o corpo, incluindo um link no título para a URL canônica da postagem.

No corpo do post, também estamos usando filtros de modelo para limitar as palavras nos trechos a 200 caracteres. Os filtros de modelo permitem que modifique variáveis para exibição e se pareçam com ficheiros {{ variable | filter }}.

Agora atualize o navegador, e visite: http://127.0.0.1:8000/ você verá a página inicial do nosso blog.

Parece bom!

Deve ter notado que importei algum conteúdo fictício para preencher a página, também pode fazer o mesmo usando ferramentas de gerador de Lorem ipsum.

Agora vamos fazer um template HTML para visualização detalhada dos nossos posts. Em seguida, crie um ficheiro templates/post_detail.html e cole o HTML abaixo.

Ficheiro: templates/post_details.html

{% extends 'base.html' %} {% block content %}<div class="container">
<div class="row">
<div class="col-md-8 card mb-4 mt-3 left top">
<div class="card-body">
<h1>{% block title %} {{ object.title }} {% endblock title %}</h1>
<p class=" text-muted">{{ post.author }} | {{ post.created_on }}</p>
<p class="card-text ">{{ object.content | safe }}</p>
</div>
</div>
{% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}
</div>
</div>
{% endblock content %}

Na parte superior, foi herdada o modelo base.html. Em seguida, exiba o objeto body do nosso contexto, que DetailView o torna acessível como um objeto.

A pasta de templates terá a seguinte estrutura:

├── templates
│ ├── base.html
│ ├── index.html
│ ├── post_detail.html
│ ├── sidebar.html

Pode agora visitar o mesmo site e clique em Read More

Django — Index page

Deve ser redirecionado para a página se se segue:

Já chegamos ao final do workshop | parte 2, mas para breve haverá continuação do workshop | parte 3.

Segue a apresentação do PowerPoint do workshop.

Se estiver a ter algum problema com uma das etapas, consulte o repositório no Github.

--

--