PYTHON DJANGO: NÃO crie sua RestFull API sem antes conhecer a ModelViewSet

Tags:

Sem sombra de dúvida, seja você um desenvolvedor experiente ou iniciante, já deve ter se deparado com o conceito ou terminologia API!

Application Programming Interface – API , é uma das formas mais comuns de serviços e aplicativos comunicarem entre si, independentemente da tecnologia, framework ou linguagem que foram usadas para o desenvolvimento dos mesmos.

Em outras palavras, seria como um idioma em comum que servisse para a troca de informações em sistemas que podem ser muito diferentes tecnologicamente.

Vamos aprender então neste tutorial como criar uma RESTFull API usando o framework Python Django, através de uma das mais vantajosas interfaces: ModelViewSet!

Criando uma API com ModelViewSet:

  • ModelViewSet:

É fato que o framework Django é conhecido por ser uma solução que une todas as maravilhas da programação em Python juntamente com um ecossistema poderoso de ferramentas a serem usadas em aplicações reais.

Dessa maneira, existem inúmeras formas de se trabalhar com o Django como um backend API, dentre elas uma das mais conhecidas é usando a biblioteca/app chamado djangorestframework: https://www.django-rest-framework.org

Além disso, esta mesma biblioteca oferece mais de uma forma de se implementar APIs, tais como por exemplo a que usaremos neste tutorial: a ModelViewSet.

É importante ressaltar que sem dúvida a maior vantagem de utilizá-la é a abstração de uma grande quantidade de código, possibilitando com que usando apenas 2 linhas de código, seja possível criar sua restfull api!

Contudo, também é importante ressaltar que uma das principais propostas da ModelViewSet é ser usada para criação de endpoints que não necessitam a implementação de muitas regras de negócio, eliminando consequentemente códigos repetitivos conhecidos como boilerplates, e embora seja possível personalizá-la, caso seu projeto necessite de muitas lógicas customizadas dentro de seus services/views, talvez seja interessante considerar outro tipo de solução.

  • Preparação do ambiente:

ATENÇÃO: Iremos partir do pressuposto que você já está com seu ambiente python configurado, bem como com o projeto base do Django criado. Caso tenha dúvidas com este procedimento, sugerimos que inicie este tutorial: Django: Primeiros Passos antes de proceder com o atual.

  • Criando o projeto:
1. Criando a virtual env:

Começaremos com um novo projeto em Django, criando a virtual environment, para isso abriremos o editor de código em uma pasta vazia, e digitaremos em seu terminal:

Obs: Para utilizar o python no terminal de comando, existe uma pequena variação caso esteja utilizando Linux ou Windows, portanto, para sistemas Windows: digite py , e para Linux: python3

py -m venv venv

Em seguida, ativaremos a venv:

Windows:

Como dica, use o complemento automático do teclado, digitando: v + (tecla TAB) + s + (tecla TAB) + a + (tecla TAB)

.\venv\Scripts\activate

Linux:

Como dica, use o complemento automático do teclado, digitando: source + v + (tecla TAB) + b + (tecla TAB) + a + (tecla TAB)

source venv/bin/activate
2. Instalando as dependências do projeto:

Além do Django, usaremos as seguintes bibliotecas/dependências:

pip install djangorestframework django-cors-headers
  • djangorestframework: uma das principais dependências do Django, usadas para trabalhar no formato de API .
    https://www.django-rest-framework.org/
  • django-cors-headers: não é de uso obrigatório para o uso do Django como API, contudo, uma vez que o principal propósito de uma API é se comunicar com outros servidores e sistemas, provavelmente você terá a necessidade de configurar o CORS da sua aplicação.
    https://pypi.org/project/django-cors-headers/

Atualize as bibliotecas instaladas no arquivo de requerimentos do Django digitando:

pip freeze > requirements.txt
3. Criando o projeto e o app:

Com o django instalado, execute o comando de criação do projeto, substituindo o nome “project” para o desejado (não é possível usar espaços e nem caracteres especiais):

Obs.: não se esqueça do “espaço” + “ponto” após o comando, para possibilitar com que o projeto seja criado na raiz do seu diretório atual.

django-admin startproject project .

Criamos em seguida o app do projeto com o comando abaixo (substitua “app” com o nome desejado) :

django-admin startapp app
4. Registrando o aplicativo:

Projeto e aplicativo criados, ok, porém o Django não irá utilizar o seu app se você não registrá-lo no projeto.

Portanto, procure dentro da pasta de seu projeto o arquivo settings.py (caso tenha usado o mesmo nome utilizado neste tutorial, estará localizado na pasta “project” )

Faça o registro do seu aplicativo e de suas bibliotecas colocando o nome do mesmo em INSTALLED_APPS presente em seu settings.py (atente-se caso tenha utilizado um nome diferente para o seu projeto, use-o no lugar do ‘app’ do código abaixo):

Dessa maneira, adicionaremos corsheaders, rest_framework e o app.

Aproveite também para adicionar a configuração de Cors para permitir todas as origens (esta configuração será usada para testes da API, já para uso em ambientes definitivos é interessante utilizar outras configurações disponíveis da biblioteca cors headers).

project/settings.py
ALLOWED_HOSTS = []

CORS_ALLOW_ALL_ORIGINS = True

# Application definition

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

Em seguida, também aproveitaremos para mudar o idioma e fuso-horário para os do Brasil:

project/settings.py
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/

LANGUAGE_CODE = 'pt-br'

TIME_ZONE = 'America/Sao_Paulo'

USE_I18N = True

USE_TZ = True
5. Primeira migração e superusuário:

Antes de prosseguirmos, iremos realizar a primeira migração do projeto, e criarmos o superusuário do mesmo, para se ter a certeza de que todos os passos anteriores foram feitos corretamente.

Digite portanto, os comandos de migração no terminal de seu editor de código com a venv ativada:

py .\manage.py makemigrations
py .\manage.py migrate

Agora criaremos o superuser:

py .\manage.py createsuperuser

Siga com o preenchimento das informações que serão solicitadas no terminal, pressionando ENTER após cada confirmação.

Para efeito de simplificação, estaremos utilizando estas credenciais: “admin”, email: “admin@admin.com”, senha: “admin”.

criação do superusuário

Executaremos o servidor, e conectaremos ao mesmo usando o endereço padrão http://localhost:8000/admin

py .\manage.py runserver

Até o momento, teremos apenas as tabelas padrão do Django, tais como Grupos e Usuários:

6. Criando as Models:

As models são basicamente as entidades / tabelas de banco de dados de sua aplicação.

Para exemplificar nossa API, iremos representar 3 entidades de uma aplicação farmacêutica: Categorias (Category), Empresa (Company) e Medicamento (Medicine).

Criaremos então dentro de models.py localizado em seu app, a primeira tabela de Categorias.

app/models.py
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=200)
    gov_registry = models.CharField(max_length=13)

    class Meta:
        verbose_name_plural = 'Categories'
    def __str__(self):
        return self.name

Aqui vão algumas observações iniciais para esclarecer o que fizemos, caso seja novidade para você:

  • a) estamos criando uma tabela de nome “Category” que conterá 3 colunas: name e category (ambos do tipo texto), e o id (implícito em qualquer model, não sendo necessário definí-lo)
  • b): por padrão o Django tem o comportamento de colocar o plural do nome da tabela na seção admin com o acréscimo de ‘s’ no final, porém como o plural de Category não é Categorys, decidimos mudar essa nomenclatura.
  • c): definimos que a conversão da classe Category em texto (string) será o próprio nome da categoria, sendo isso útil quando se usa a interface admin do Django para relacionamento de chaves estrangeiras.

Agora iremos criar a tabela de Empresas:

app/models.py
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=200)
    gov_registry = models.CharField(max_length=13)

    class Meta:
        verbose_name_plural = 'Categories'
    def __str__(self):
        return self.name


class Company(models.Model):
    name = models.CharField(max_length=200)
    cnpj = models.CharField(max_length=15)
    address = models.CharField(max_length=300)
    created_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'Companies'
    def __str__(self):
        return self.name

Alguns comentários sobre a classe criada:

  • a) estamos criando uma tabela de nome “Company” que conterá 5 colunas: name, cnpj, address (todos do tipo texto), created_date (campo do tipo Data e Hora que será adicionado automaticamente toda vez que um registro novo for inserido na tabela) e, finalmente o id (implícito em qualquer model, não sendo necessário definí-lo)

Finalmente iremos criar a última classe de Medicamentos:

app/models.py
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=200)
    gov_registry = models.CharField(max_length=13)

    class Meta:
        verbose_name_plural = 'Categories'
    def __str__(self):
        return self.name


class Company(models.Model):
    name = models.CharField(max_length=200)
    cnpj = models.CharField(max_length=15)
    address = models.CharField(max_length=300)
    created_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'Companies'
    def __str__(self):
        return self.name
    
class Medicine(models.Model):
    name = models.CharField(max_length=200)
    category_fk = models.ForeignKey(Category, related_name="medicineCategory", on_delete=models.CASCADE)
    company_fk = models.ForeignKey(Company, related_name="medicineCompany", on_delete=models.CASCADE)
    cost = models.DecimalField(max_digits=10,decimal_places=2)
    is_generic = models.BooleanField(default=False)
    created_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

Algumas informações importantes sobre o código acima:

  • a) estamos criando uma tabela de nome “Medicine” que conterá 6 colunas: name (tipo texto), category_fk (chave estrangeira que se relaciona com a model Category), company_fk(chave estrangeira que se relaciona com a model Company), cost (tipo número com 2 escalas decimais), is_generic (tipo booleano com valor falso como padrão), created_date (campo do tipo Data e Hora que será adicionado automaticamente toda vez que um registro novo for inserido na tabela) e, finalmente o id (implícito em qualquer model, não sendo necessário definí-lo)
  • b) o código models.ForeignKey é utilizado para criar relacionamento entre tabelas do banco de dados, ou seja, somente pode ser criado um medicamento usando uma categoria e empresa que já esteja cadastrada na aplicação.
7. Registrando as models em admin:

Para que todas as models criadas estejam disponíveis na tela de administração do Django, precisaremos registrá-las em admin.py:

Observe que para a tabela Medicine, opcionalmente estamos customizando como queremos que seja mostrada no ambiente admin, definindo inclusive que os campos ‘name’ e ‘category_fk’ serão usados como chave de pesquisa na tela de administração.

app/admin.py
from django.contrib import admin
from .models import *

#registrando as models criadas na tela de admin do Django:

admin.site.register(Category)
admin.site.register(Company)

class adminMedicine(admin.ModelAdmin):
    list_display = ('id', 'name', 'category_fk', 'company_fk')
    list_display_links = ('id', 'name',)
    search_fields = ('name','category_fk',)
    list_per_page = 10

admin.site.register(Medicine, adminMedicine)
8. Migrando as novas tabelas:

Digitaremos os comandos de migração no terminal do projeto com a venv ativada:

py .\manage.py makemigrations
py .\manage.py migrate

Podemos visualizar então a criação das tabelas:

Ao acessar a tela de administração do Django com o superusuário criado anteriormente, poderemos visualizar as novas tabelas:

9. Criando os Serializers:

Finalmente agora pensaremos em nossa API!

Você deve já saber que um dos padrões mais utilizados para comunicação com API’s é o famoso JSON (Javascript Object Notation).

Desse modo, precisaremos criar os chamados Serializers, responsáveis pela conversão dos dados em Pyhton em JSON e vice-versa.

Criaremos então o arquivo serializers.py dentro da pasta de nosso app:

Digitaremos o código abaixo para informar que desejaremos que todos os campos de cada tabela/models seja passível de conversão para JSON:

app/serializers.py
from rest_framework import serializers
from .models import *

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'
        many = True

class CompanySerializer(serializers.ModelSerializer):
    class Meta:
        model = Company
        fields = '__all__'
        many = True

class MedicineSerializer(serializers.ModelSerializer):
    class Meta:
        model = Medicine
        fields = '__all__'
        many = True
10. Criando as Views da API com ModelViewSet:

Quando o Django é utilizado como solução fullstack para renderização de html, as views são usadas para definição das rotas das páginas a serem visualizadas no frontend.

Contudo, nosso foco de utilização do Django neste projeto é usá-lo como solução backend. Desse modo, as views serão responsáveis por implementar o funcionamento essencial de uma API: os protocolos http GET, POST, PUT e DELETE.

Dessa maneira, criaremos a implementação da primeira API de Categoria com o código abaixo:

app/views.py
from .models import *
from .serializers import *
from rest_framework.viewsets import ModelViewSet


class CategoryView(ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

Não se engane, neste pequeno trecho de código temos operações importantes acontecendo:

Como pode ter notado, com apenas 2 linhas de código, usando a ModelViewSet é possível criar automaticamente todas as operações básicas de qualquer API, realizando o que chamamos de CRUD: Create (Criar novos dados), Read (Consultar dados), Update (Atualizar dados), Delete (Deleter dados).

  • a) Como pode ter notado, com apenas 2 linhas de código, usando a ModelViewSet é possível criar automaticamente todas as operações básicas de qualquer API, realizando o que chamamos de CRUD: Create (Criar novos dados), Read (Consultar dados), Update (Atualizar dados), Delete (Deleter dados).
  • b) em queryset, estamos informando à ModelViewSet como será obtida a fonte dos dados da API, que neste caso consiste na seleção de todos os registros existentes na tabela de Categoria, através do Category.objects.all()
  • c) em serializer_class , estamos referenciando qual serializer será utilizado para conversão Python <–> JSON, portanto estamos usando o Serializer criado anteriormente.
  • d) A ModelViewSet segue os padrões de uma API RESTFULL, portanto cada operação do CRUD, é delegada a um método Http específico, conforme imagem abaixo:

Criaremos agora o restante das views usando o mesmo conceito explicado:

app/views.py
from .models import *
from .serializers import *
from rest_framework.viewsets import ModelViewSet


class CategoryView(ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer


class CompanyView(ModelViewSet):
    queryset = Company.objects.all()
    serializer_class = CompanySerializer


class MedicineView(ModelViewSet):
    queryset = Medicine.objects.all()
    serializer_class = MedicineSerializer

10. Criando as Urls / Endpoints da API:

Outra parte muito importante de uma API é a criação dos pontos de acesso (endpoints) que ficarão disponibilizados para uso dos sistemas que queiram comunicar-se com a API criada!

Criaremos então um novo arquivo chamado urls.py dentro de nosso app (não confunda com o urls.py que já existe dentro de seu projeto).

Neste arquivo então definiremos uma rota/caminho desejado para acionamento de cada view criada anteriormente:

app/urls.py
from .views import *
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'category',CategoryView)
router.register(r'company',CompanyView)
router.register(r'medicine',MedicineView)

urlpatterns = router.urls

Criamos as urls em nosso app, OK!

Porém agora necessitaremos registrá-las em nosso projeto, caso contrário, elas não serão válidas (este erro é muito comum em iniciantes distraídos).

Localize então a urls.py de seu projeto:

Faça a importação do django.urls include, e utilize-o para incluir as urls existentes em seu app (substitua a palavra “app” pelo nome que usou durante a criação do mesmo, caso tenha adotado um diferente do que foi usado neste tutorial).

project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('app.urls')),
]

11. Executando o projeto:

Finalmente é chegada a hora de testarmos o resultado de nosso trabalho!

Para isso, digite no terminal de seu editor de código com a venv ativada, os comandos de execução do projeto:

py .\manage.py runserver
11. Testando a API com RestFramework interface:

A biblioteca djangorestframework que instalamos no início do projeto, além de possibilitar a criação de nossa API, também providencia um ambiente de teste de API semelhante ao famoso Swagger, dispensando o uso ferramentas externas caso o desenvolvedor prefira.

Para isso, basta acessar o endereço raiz de seu servidor, por padrão sendo: http://localhost:8000/

Com esta interface, é possível utilizar os métodos GET, POST, PUT e DELETE para cada endpoint.

Faremos então um teste inicial com o endpoint de categoria (/category), para isso você pode alterar a url do browser ou clicar no link que deve aparecer em sua interface “http://127.0.0.1:8000/category/”:

Colocaremos então as informações necessárias para se criar uma Categoria, ou seja, Nome e Código de registro:

Você deve obter a resposta de êxito em JSON:

12. Testando a API com interface Admin:

Acesse a tela de admin do django, utilizando o superusuário que criou no início do projeto, seguindo os mesmos procedimentos que você já fez neste tutorial:

Outra opção é adicionar uma nova categoria através da interface de administração, clicando em + Adicionar:

Preenchendo as mesmas informações para se criar uma categoria, você também poderá obter o mesmo resultado de adição:

13. Testando a API com Insomnia:

Uma das principais formas de se testar APIs é usando ferramentas como Insomnia ou Postman, onde podem ser baixadas gratuitamente no site oficial de cada uma (para efeito demonstrativo, usaremos neste tutorial o Insomnia):

Insomnia: https://insomnia.rest/download

Postman: https://insomnia.rest/download

Faremos inicialmente um GET para o endpoint de categorias, onde será possível obter os dados cadastrados nas operações anteriores em JSON:

Agora executaremos o envio de uma nova categoria via POST enviando um JSON no Body (corpo) da requisição:

Para testarmos o endpoint de atualização de dados, usaremos o id de uma categoria já criada, alterando um dos dados cadastrados:

Agora faremos um novo GET para verificar se o dado foi realmente alterado:

Por fim, testaremos o endpoint de deleção dos dados com o DELETE, passando o id da categoria a ser excluída:

14. Testando os relacionamentos da API:

Agora que já fizemos vários testes com o endpoint de Categoria, iremos executar a adição de Empresas (Company) e usá-las no cadastramento de novos medicamentos (Medicine):

Cadastraremos novas companhias:

Para o cadastramento de um medicamento, precisamos relacionar uma categoria e uma empresa já criadas anteriormente, para isso demonstraremos como realizar via tela de administração e pelo insomnia, respectivamente:

Conclusão

Finalizamos este tutorial conseguindo criar com apenas alguns passos uma Restfull API!

Utilizando os benefícios da abstração da ModelViewset, você pôde perceber que literalmente com apenas duas linhas de código é possível implementar todas as operações de um CRUD.

Além disso, conseguiu observar que o Django possibilita inúmeras formas de gerenciamento e teste de sua API, seja através do ambiente nativo de administração, ou pela interface visual da biblioteca djangorestframework e, por fim usando ferramentas externas como Insomnia, Postman, entre outras.

Como sempre abordamos em nossos tutoriais, existem muitos caminhos ainda a percorrer para conseguir autonomia na criação de projetos complexos com frameworks, sendo fundamental para o desenvolvedor procurar novos conteúdos e se aprofundar em novos conceitos.

Convidamos para que explore mais opções de conteúdo relacionadas com este ou outros frameworks em nosso site!

Faça o download do projeto em nosso github:

    Deixe um comentário

    O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *