Skip to main content

A simple ORM for SQLite databases in Python.

Project description

SQLITE ORM - Um Wrapper para utilização simplificada do sqlite3

Visão Geral da Arquitetura

O SQLiteORM é uma biblioteca de mapeamento objeto-relacional (ORM) desenvolvida para facilitar a interação com bancos de dados SQLite. Ele abstrai a complexidade das operações SQL, permitindo que os desenvolvedores trabalhem com objetos Python para realizar operações no banco de dados.

Instalação

Para instalar o SQLiteORM no seu projeto, rode o seguinte comando no terminal:

pip install python-sqlite3-orm

Componentes Principais

  1. clauses.py:

    • Define as cláusulas SQL, como WHERE, ORDER BY, LIMIT e OFFSET.
    • Contém classes como QueryClauses e ClauseGenerator para gerar partes específicas de uma query SQL.
  2. database_manager.py:

    • Gerencia conexões com o banco de dados SQLite.
    • Fornece um gerenciador de contexto para garantir que as conexões sejam abertas e fechadas corretamente.
  3. db_session.py:

    • Gerencia sessões de interação com o banco de dados.
    • Permite configurar filtros, ordenação e outras opções para consultas.
  4. field.py:

    • Define os tipos de campos disponíveis para os modelos, como Integer e String.
    • Implementa validações e o protocolo de descritores para gerenciar o acesso aos dados.
  5. model.py:

    • Define a metaclasse ModelMeta para processar atributos de classe e configurar metadados, como o nome da tabela e os campos.
    • Permite que os modelos representem tabelas no banco de dados.

Fluxo de uma query

  1. Definição de Campos

    • O desenvolvedor pode definir campos a serem utilizados dentro de seus modelos. Ao estruturar uma tabela no banco de dados, o desenvolvedor deve definir o nome do campo e as suas especificidades. Por exemplo, ao definir um tabela "Users" com id, nome, cpf e idade, poderia ser utilizado a seguinte query SQL:
    CREATE TABLE Users (
       id INTEGER PRIMARY KEY,
       nome VARCHAR(100) NOT NULL,
       cpf VARCHAR(11) NOT NULL UNIQUE,
       idade INTEGER
    );
    

    Os campos (Integer, Varchar, ...) foram abstraídos para a classe Field.

    class Field(ABC):
     """
     Base class for all field types in the ORM.
     """
    
       def __init__(
          self,
          *,
          type: str, 
          primary_key: bool = False, 
          nullable: bool = True, 
          unique: bool = False
       ) -> None:
    
       ...
    

    Alguns campos mais comuns foram definidos no pacote field, sendo eles:

    • Integer: Tipo genérico para números inteiros.
    • ID: Um campo inteiro especial usado como chave primária única.
    • BigInteger: Um campo para números inteiros grandes.
    • Decimal: Representa números decimais com precisão e escala configuráveis.
    • String: Um campo para strings com comprimento máximo configurável.
    • Boolean: Representa valores booleanos (True ou False).
    • Float: Um campo para números de ponto flutuante.
    • Text: Um campo para strings longas.
    • Blob: Representa dados binários, como imagens ou arquivos.
    • DateTime: Um campo para armazenar data e hora no formato ISO 8601.
    • Date: Representa apenas a data no formato ISO 8601.
    • Time: Representa apenas o horário no formato ISO 8601.

    O usuário pode criar novos tipos de dados.

    from sqlite_orm.field import Field
    
    class NewField(Field):
       def __init__(self, *args, **kwargs) ->  None:
          super().__init__(type='NEW_FIELD', **kwargs)
    
       def __validate__(self, value):
          # Implementação do validador
          raise NotImplementedError()
    

    [!INFO] Para a criação de novos campos, é obrigatório a implementação de um validador, que indica se o valor fornecido na criação do modelo é válido.

  2. Definição do Modelo:

    • O desenvolvedor define uma classe que herda de Model e especifica os campos como instâncias de Field. Ademais, é necessário ser indicado o nome da tabela com o campo 'tablename'.
    from sqlite_orm.model import Model
    from sqlite_orm.field import ID, Integer, String
    
    class User(Model):
       __tablename__ = "Users"
    
       id = IntegerID()
       name = String(max_length=100, nullable=False)
       cpf = String(max_length=11, nullable=False, unique=True)
       idade = Integer()
    
    • Para criar uma nova instância de um modelo, basta seguir o processo de criação de um dataclass.
    user = User(id=1, nome='Fulano da Silva', cpf='12345678900', idade =20)
    
  3. Criação da Sessão:

    • Uma instância de DatabaseContextManager é usada para gerenciar a conexão com o banco de dados.
    from sqlite_orm.database_manager import DatabaseContextManager, DBSession
    
    with DatabaseContextManager("example.db") as db:
        session = db.get_session(User)
    

    caso o desenvolvedor deseje que sejam exibidas as queries que estão sendo executadas, basta usar o método debug com o parâmetro enable definida como True.

    from sqlite_orm.database_manager import DatabaseContextManager, DBSession
    
    with DatabaseContextManager("example.db") as db:
        session = db.get_session(User).debug(enable=True)
    
    # Ou
    
    with DatabaseContextManager("example.db") as db:
        session = db.get_session(User)
    
        session.debug(enable=True, in_place=True)
    
  • SELECT

  1. Configuração da Query:

    • O desenvolvedor configura filtros, ordenação e outras opções usando SessionOptions.
    from sqlite_orm.database_manager import DatabaseContextManager, DBSession
    
    with DatabaseContextManager("example.db") as db:
        session = db.get_session(User)
    
        session = session.select().all()
    

    para uma query SELECT é preciso indicar se serão retornados vários objetos (lista) ou apenas um objeto (tupla ou Model).

    session = session.select().all()
    # OU
    session = session.select().first()
    

    Poder ser escolhido pelo usuário se o retorno da função será dado em uma tupla ou como uma instância do modelo criado anteriormente, através do método to_model().

    Exemplos de retorno:

    session = session.select().all()
    # [(1, 'Fulando da Silva', '12345678900', 20)]
    
    session = session.select().first()
    # (1, 'Fulando da Silva', '12345678900', 20)
    
    session = session.select().all().to_model()
    # [<User (id=1, nome='Fulando da Silva', cpf='12345678900', idade=20)>]
    
    session = session.select().first().to_model()
    # <User (id=1, nome='Fulando da Silva', cpf='12345678900', idade=20)>
    
  2. Execução da Query:

    • Para que a query seja executada, é necessário utilizar o método execute.
    results = session.select().all().to_model().execute()
    for user in results:
        print(user.name)
    
  3. Filtros no SELECT (recomendado: Expressions)

    A forma recomendada para filtrar é utilizar Expressions diretamente nos campos do modelo, com operadores Python. Esse formato é mais legível combinável e simples de manter.

    users = (
         session
         .select()
         .all()
         .where((User.age > 18) & (User.name.like("A%")))
         .to_model()
         .execute()
    )
    

    Todas as formas de filtro suportadas hoje:

    1. Expression simples (recomendado)
    session.select().all().where(User.id == 1).execute()
    session.select().all().where(User.age >= 18).execute()
    session.select().all().where(User.name != "John").execute()
    
    1. Expression composta com operadores lógicos (recomendado)
    session.select().all().where((User.age > 18) & (User.name.like("J%"))).execute()
    session.select().all().where((User.age < 18) | (User.name == "Admin")).execute()
    session.select().all().where(~(User.name.like("%teste%"))).execute()
    
    1. LIKE, IN e NOT IN com Expression (recomendado)
    session.select().all().where(User.name.like("%John%")).execute()
    session.select().all().where(User.id.in_([1, 2, 3])).execute()
    session.select().all().where(User.id.not_in([4, 5])).execute()
    
    1. Comparações com NULL (recomendado)
    session.select().all().where(User.name == None).execute()  # IS NULL
    session.select().all().where(User.name != None).execute()  # IS NOT NULL
    
    1. Atalho por kwargs com igualdade
    session.select().all().where(id=1).execute()
    session.select().all().where(name="Alice").execute()
    
    1. Modo legado com QueryFilter (compatibilidade)
    from sqlite_orm.query_filter import Equals, GreaterThan, Like, In, AND, OR
    
    session.select().all().where(id=Equals(1)).execute()
    session.select().all().where(age=GreaterThan(18)).execute()
    session.select().all().where(name=Like("%John%")).execute()
    session.select().all().where(id=In([1, 2, 3])).execute()
    
    session.select().all().where(
         OR(
             AND(name=Equals("John"), age=GreaterThan(18)),
             AND(name=Like("%Admin%"), age=GreaterThan(60))
         )
    ).execute()
    

    [!TIP] Para novos projetos e novas consultas, prefira Expressions. QueryFilter, AND e OR continuam disponíveis para compatibilidade com código legado.

Exemplos de Código

Criação de Tabelas

   from sqlite_orm.model import Model
   from sqlite_orm.field import ID, Integer, String
   from sqlite_orm import DatabaseContextManager, DBSession

   class User(Model):
      __tablename__ = "Users"

      id = IntegerID()
      name = String(max_length=100, nullable=False)
      cpf = String(max_length=11, nullable=False, unique=True)
      idade = Integer()

   with DatabaseContextManager("example.db") as db:
       session = db.get_session(User)
       session.create_table().execute()

Deleção de Tabelas

   from sqlite_orm.model import Model
   from sqlite_orm.field import ID, Integer, String
   from sqlite_orm import DatabaseContextManager, DBSession

   class User(Model):
      __tablename__ = "Users"

      id = IntegerID()
      name = String(max_length=100, nullable=False)
      cpf = String(max_length=11, nullable=False, unique=True)
      idade = Integer()

   with DatabaseContextManager("example.db") as db:
       session = db.get_session(User)
       session.drop_table().execute()

Inserindo Dados

from sqlite_orm.model import Model
from sqlite_orm.field import ID, String
from sqlite_orm import DatabaseContextManager, DBSession

class Product(Model):
    id = IntegerID()
    name = String(nullable=False)

with DatabaseContextManager("store.db") as db:
    session = db.get_session(Product)
    product = Product(name="Laptop")
    session.insert(product)
    id = session.execute() # Retorna o id do objeto inserido no banco de dados

    product = session.select() \
      .first() \
      .where(Product.id == id) \
      .to_model() \
      .execute()

    print(product.name) # Laptop

Atualizando Dados

with DatabaseContextManager("store.db") as db:
    session = db.get_session(Product)
    session.update() \
    .set(name = "Gaming Laptop") \
    .where(Product.id == 1) \
    .execute()

Deletando Dados

with DatabaseContextManager("store.db") as db:
    session = db.get_session(Product)
    session.delete() \
    .where(Product.id == 1) \
    .execute()

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

python_sqlite3_orm-2.1.0.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

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

python_sqlite3_orm-2.1.0-py3-none-any.whl (21.8 kB view details)

Uploaded Python 3

File details

Details for the file python_sqlite3_orm-2.1.0.tar.gz.

File metadata

  • Download URL: python_sqlite3_orm-2.1.0.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for python_sqlite3_orm-2.1.0.tar.gz
Algorithm Hash digest
SHA256 8cb420944022bd5176d58b7d0fc5b294104c7e27a5541a908f3f25506b21fc12
MD5 e4f1c3b0ef43f9f041e8f3fe04a342b3
BLAKE2b-256 87a4fff007e89043f8ef780c261d0349db84b150a8cb23d29e14f0d14be2b909

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_sqlite3_orm-2.1.0.tar.gz:

Publisher: publish.yml on Wanderson-Patricio/sqlite-orm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_sqlite3_orm-2.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for python_sqlite3_orm-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97d3021bea53b7e36d1fca0e07dfdce7ed26051fdb7ff627008dad112eb61b0a
MD5 2b2f03060fbee6b286dc29e342d0279a
BLAKE2b-256 8d81aa624617f9015714a1c280d63f864e7107b084844bb2d2caa6629cd0b8a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_sqlite3_orm-2.1.0-py3-none-any.whl:

Publisher: publish.yml on Wanderson-Patricio/sqlite-orm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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