Skip to main content

Django framework da Inscode.

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_inscode-0.1.21.tar.gz (24.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_inscode-0.1.21-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file django_inscode-0.1.21.tar.gz.

File metadata

  • Download URL: django_inscode-0.1.21.tar.gz
  • Upload date:
  • Size: 24.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for django_inscode-0.1.21.tar.gz
Algorithm Hash digest
SHA256 09158082055053a59639ca790bd78723c900b4fc93785c6bad056c4c38e2922c
MD5 231fb5d2c95fae628bd91691ffb750f8
BLAKE2b-256 82c1e329691ee04057c1b283d887580bd91a67adc4ef51a247221cc716eb15af

See more details on using hashes here.

File details

Details for the file django_inscode-0.1.21-py3-none-any.whl.

File metadata

File hashes

Hashes for django_inscode-0.1.21-py3-none-any.whl
Algorithm Hash digest
SHA256 1ddb6edeb3ffbbc77fbf5e2479611d80dc94fa829036c758c813bb8513a7a689
MD5 22dee763ee1cdced57f536a1e249317a
BLAKE2b-256 fc189f53da88acebf061848bf8c51d1a29e38715363c2e34e64db7f888bf2021

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page