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.2.1.tar.gz (19.8 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.2.1-py3-none-any.whl (24.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: python_sqlite3_orm-2.2.1.tar.gz
  • Upload date:
  • Size: 19.8 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.2.1.tar.gz
Algorithm Hash digest
SHA256 10fc6079469acbc5ca7548518e08b34291c6ea1683ac5c49c643e3080af6e17d
MD5 a7f613f70e30118f59db6630c5f528a3
BLAKE2b-256 d0d1ccb96e016bf8e9122ff1870515b6bcdd6b4c80771835ca250620394c1795

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_sqlite3_orm-2.2.1.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.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for python_sqlite3_orm-2.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c61799068ad7ea45a9c80e08138e435b1b9550ce42d881afa768a9479bd3021d
MD5 0aaecae0f63ff02e23cb2cb744bac25e
BLAKE2b-256 b90557dc722dc5918239d951255ddfee316df6d1ab8c09d3a4e432a078d16118

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_sqlite3_orm-2.2.1-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