Skip to main content

django-inscode

Django-inscode é um framework Django que tem como objetivo implementar um padrão de camadas baseado em serviços e repositórios para criação de projetos backend da empresa Inscode.

Este projeto fornece classes e funções personalizadas para:

  • Modelos ORM
  • Modelos de transporte
  • Repositórios
  • Serviços
  • Views
  • Permissões

Modelos ORM

São fornecidos dois modelos bases possíveis de serem utilizados:

  • BaseModel -- Classe base com uma chave primária do tipo UUI4.
  • SoftDeleteBaseModel -- Classe base com uma chave primária do tipo UUI4 e cujas instância são excluidas apenas logicamente (usando a flag is_deleted).

Exemplo

from django_inscode.models import SoftDeleteBaseModel
from django.db import models

class Book(SoftDeleteBaseModel):
  name = models.CharField(max_length=100)

Modelos de transporte

Modelos de transporte irão servir como um guia para definir como objetos ORM serão serializados e retornados pela API. Para todo modelo do banco de dados deverá existir um modelo de transporte equivalente.

O django-inscode fornece suporte para dois tipos de objetos de transporte distintos: Um modelo interno chamado Transport e um Schema da biblioteca marshmallow.

Transport

Esta classe deverá ser descontinuada, porém para projetos que utilizam versões mais antigas do django-inscode ela é a única solução possível.

Para definir uma classe de transporte deve-se import a classe Transport.

Exemplo

from django_inscode.transports import Transport
from dataclasses import dataclass

@dataclass(frozen=True)
class BookTransport(Transport):
  name: str

Marshmallow Schema

Esta é a classe de transporte recomendada para novos projetos em desenvolvimento que utilizam a biblioteca django-inscode.

Exemplo

from marshmallow import Schema, fields

class BookTransport(Schema):
  name = fields.Str()

Repositórios

Repositórios são boas interfaces para garantir uma interação tranquila entre a aplicação e o banco de dados. Um repositório funciona criando e buscando dados no banco de dados e retornando objetos ORM relacionados.

Desse modo, ao utilizar a biblioteca django-inscode não se deve usar instâncias de objetos ORM, mas sim seus repositórios.

Exemplo

from django_inscode.repositories import Repository
from .models import Book

book_repository = Repository(Book)

 # Cria um novo livro
book = book_repository.create(name="Novo livro")
 # Atualiza livro
updated_book = book_repository.update(book.id, name="Novo livro atualizado")
retrieved_book = book_repository.read(book.id) # Retorna o livro
 # Retorna todos os livros com o nome dado
filtered_books = book_repository.filter(name="Novo livro atualizado")
 # Retorna todos os livros
all_books = book_repository.list_all()
 # Exclui o livro
book_repository.delete(book.id)

Serviços

Serviços são utilizados para encapsular lógicas de negócios da aplicação. Um serviço pode ser do tipo Model ou do tipo Orchestrator.

Em uma arquitetura em camadas, um serviço depende de um ou mais repositórios para controlar suas ações.

Serviços de modelo

Serviços de modelo são adequados para operações CRUD sobre modelos da aplicação. Na classe de serviço é possível validar dados de uma requisição e também sobrescrever métodos para lidar com lógicas de negócio personalizadas.

Para todo modelo criado, é necessário criar um repositório e uma classe de serviço para ele.

Exemplo

from django_inscode.services import ModelService
from django_inscode import exceptions

from .repositories import book_repository

class BookService(ModelService):
  def validate(self, data, instance):
    name = data.get("name")

    if name is not None and self.repository.filter(name=name).exists():
      raise exceptions.UnprocessableEntity(errors={"name": "Já existe um livro com este nome."})

  def create(self, data, context):
    # Adicionar, caso precise, alguma lógica de negócio
    return super().create(data, context)

  def read(self, data, context):
    # Adicionar, caso precise, alguma lógica de negócio
    return super().read(data, context)

  def update(self, data, context): 
    # Adicionar, caso precise, alguma lógica de negócio
    return super().update(data, context)

  def delete(self, data, context):
    # Adicionar, caso precise, alguma lógica de negócio
    return super().update(data, context)

book_service = BookService(book_repository)

No exemplo, data é um dicionário contendo os itens da requisição e context é um dicionário com informações adicionais da requisição HTTP como o usuário e a sessão.

Exemplo

from django_inscode.services import ModelService
from django_inscode import exceptions

class BookService(ModelService):
  def create(self, data, context):
    user = context["user"]
    session = context["session"]

    # Alguma lógica com user ou session

    return super().create(data, context)

Há também casos onde desejamos realizar apenas algumas ações sobre um modelo. Por exemplo, pode haver um caso em que seja desejado apenas ações de criar e ver modelos. Neste caso, utiliza-se a classe GenericModelView e define-se as ações desejadas com mixins.

Exemplo

from django_inscode.services import GenericModelService
from django_inscode import mixins

from .repositories import book_repository

class BookService(mixins.ServiceCreateMixin, mixins.ServiceReadMixin, GenericModelService):
  pass

# Serviço com ações apenas de criar, ler e listar.
book_service = BookService(book_repository)

Serviços orquestradores

Em muitas ocasiões é necessário realizar ações na API que não sejam relacionadas ao CRUD de algum modelo. É comum algumas lógicas de negócio que utilizem várias regras para retornar um resultado. Neste caso, é necessário utilizar serviços orquestradores.

Serviços orquestradores funcionam ao utilizar um ou vários repositórios para realizer uma ação na aplicação.

Exemplo

from django_inscode.services import OrchestratorService

import requests
import json

class EnviaNomesDosLivrosParaAPIExternaService(OrchestratorService):
  def execute(self, *args, **kwargs):
    # A lógica principal de um serviço orquestrador deve estar na função execute.
    url = "https://api.exemplo.com/endpoint"

    books = book_repository.list_all()
    books_names = list(map(lambda book: book.name, books))

    headers = {
        "Content-Type": "application/json",
    }

    response = requests.post(url, data=json.dumps(dados), headers=headers)

    if response.status_code == 200:
      return {"message": "Dados enviados com sucesso."}
    else:
      return {"message": "Erro ao enviar dados."}

Serviços orquestradores também podem receber dados de uma requisição e um contexto.

Exemplo

class AlgumOrquestradorService(OrchestratorService):
  def execute(self, *args, **kwargs):
    data = kwargs.get("data")
    context = kwargs.get("context")
    ...

Observação: Serviços orquestradores devem sempre retornar dicionários.

Views

O django-inscode fornece views prontas para lidar com serviços orquestradores e serviços de modelo, sem precisar realizar configurações adicionais.

Views de modelo

Views de modelo representam os endpoints para acessar os serviços de modelo.

Exemplo

from django_inscode.views import ModelView
from django_inscode.permissions import IsAuthenticated

 # Maneira antiga
from django_inscode.serializers import Serializer

from .models import Book
from .transports import BookTransport
from .services import BookService


class BookView(ModelView):
   # define os campos obrigatórios da requisição
  fields = ["name"]
   # define as permissões para acesso à view
  permissions = [IsAuthenticated]
   # serviço que irá realizar as ações
  service = book_service
   # parâmetro de busca da url
  lookup_field = "id"
  # serializer = Serializer(Book, BookTransport) !!!Maneira antiga usando a classe Transport!!!
  # Maneira mais recente usando marshmallow e schema
  serializer = BookTransport

Esta view irá fornecer de maneira automática os métodos de POST, GET (Retrieve), GET (List com paginação), PATCH, PUT e DELETE.

Exemplo

from .views import BookView

urlpatterns = [
  path("book/", BookView.as_view()),
  path("book/<pk:id>/", BookView.as_view())
]

Nos casos em que exitam serviços de modelo que possuam apenas algumas ações, como no exemplo do livro com apenas opções de create e retrieve, também é possível limitar estes acessos na própria view. Neste caso é necessário utilizar a classe GenericModelView

Exemplo

from django_inscode.views import GenericModelView
from django_inscode.permissions import IsAuthenticated
from django_inscode import mixins

from .models import Book
from .transports import BookTransport
from .services import BookService


class BookView(mixins.ViewCreateModelMixin, mixins.ViewRetrieveModelMixin, GenericModelView):
  fields = ["name"]
  permissions = [IsAuthenticated]
  service = book_service
  lookup_field = "id"
  serializer = BookTransport

Views orquestradoras

Uma View orquestradora atua em cima de serviços orquestradores já discutidos. Esta View aceita campos obrigatórios, permissões e serviços.

Exemplo

from django_inscode.views import GenericOrchestratorView

from .services import orchestrator_service_mock

class ExampleOrchestratorView(GenericOrchestratorView):
  permissions = [IsAuthenticated]
  fields = []
  service = orchestrator_service_mock

  def post(self, request, *args, **kwarg):
    return self.execute(request, *args, **kwargs)

Como uma view orquestradora pode operar sobre qualquer método http, então é necessário especificar qual método deseja-se utilizar.

Permissões

O django-inscode fornece a classe BasePermission para criar permissões customizadas para serem utilizadas em views.

Uma permissão pode atuar a nível de view e a nível de objeto.

Exemplo

from django_inscode.permissions import BasePermission

class IsAdminOrReadOnly(BasePermission):
  """
  Permite acesso total apenas para administradores.
  Usuários não autenticados ou não administradores podem apenas ler os dados.
  """

  def has_permission(self, request, view):
    # Permite requisições GET, HEAD ou OPTIONS para todos os usuários
    if request.method in ["GET", "HEAD", "OPTIONS"]:
      return True
    
    # Para outras requisições (POST, PUT, PATCH, DELETE), apenas administradores são permitidos
    return request.user.is_authenticated and request.user.is_staff

  def has_object_permission(self, request, view, obj):
    # Regras de permissão específicas para um objeto individual
    return True

Permissões em Views orquestradoras

Permissões feitas para views orquestradoras não irão verificar o método has_object_permission. Isto ocorre pois os serviços orquestradores não atuam sobre uma instância em específico de um modelo.

Desta forma, para permissões utilizadas em views orquestradoras, basta implementar o método has_permission.

Combinação de permissões

O django-inscode permite combinar classes de permissões para formar uma nova permissão.

Exemplo

IsA : BasePermission
IsB: BasePermission

# Cria uma nova permissão IsC tal que IsC = IsA AND IsB
IsC = IsA & IsB

# Cria uma nova permissão IsD tal que IsD = IsA OR IsB
IsD = IsA | IsB

# Cria uma nova permssão IsE tal que IsE = IsA AND NOT IsB
IsE = IsA & ~IsB

# Cria uma nova permissão IsF tal que IsF = IsA OR NOT IsB
IsF = IsA | ~IsB

Metadata

Release files for django-inscode 4.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-inscode 4.0.0
File Size Uploaded
django_inscode-4.0.0.tar.gz 40.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-inscode 4.0.0
File Interpreter ABI Platform
django_inscode-4.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 85.7 kB

Release files / django_inscode-4.0.0.tar.gz

Download URL django_inscode-4.0.0.tar.gz
Size 40.0 kB
Tags Source
SHA-256 checksum
How to use checksums
327f611f87aa81b861833b84e09d4d6c503b237ce5a20ac7c525297a2e463738
BLAKE2b-256 checksum
How to use checksums
965807904cc41ef7ac847e88107b83de4f77e36f1d3094ce3a9c8465fc19c9e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / django_inscode-4.0.0-py3-none-any.whl

Download URL django_inscode-4.0.0-py3-none-any.whl
Size 45.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
89c2710d295ea2fcc08873fedacfc2c35c3cc90e3ab55b673b87963118a543b0
BLAKE2b-256 checksum
How to use checksums
a6d891bbb5d013a4c89d90e8638b5ed1e6876a60b9177ae8b40264cfabb6a638
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

4.0.0 This release

2 release files

3.0.0

2 release files

2.0.0

2 release files

1.7.8

2 release files

1.7.7

2 release files

1.7.6

2 release files

1.7.5

2 release files

1.7.4

2 release files

1.7.3

2 release files

1.7.2

2 release files

1.7.1

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.1.24

2 release files

0.1.23

2 release files

0.1.22

2 release files

0.1.21

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page