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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_inscode-1.3.0.tar.gz.
File metadata
- Download URL: django_inscode-1.3.0.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5dc730a65048ea9b8b8bd40a356579b599910f5a89a2e48b27bfda280e8499f
|
|
| MD5 |
b55895a3e7e4a072a274f0636e3e680f
|
|
| BLAKE2b-256 |
6f6f521aa52a97e6979ea720aa3b41f17b15a16d4a0415e4648f65fd0c69249f
|
File details
Details for the file django_inscode-1.3.0-py3-none-any.whl.
File metadata
- Download URL: django_inscode-1.3.0-py3-none-any.whl
- Upload date:
- Size: 26.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35743bd37806b2990705bd97fd2f4838fc264beb1b8979c65dc018a32d11defa
|
|
| MD5 |
29f1fa48b35018f92b4d04680225bbef
|
|
| BLAKE2b-256 |
78b5b7e484adeefe1db135a4dbca73fda3abaa9968c6e5ea693c70588d176c6c
|