Skip to main content

A flexible ORM extension for defining and managing views (including materialized ones) in SQLAlchemy

Project description

SQLAlchemy-ViewORM

A flexible library for defining and managing SQL views, including materialized views, in SQLAlchemy ORM.

PyPI version License: MIT Python Versions Tests

Overview

SQLAlchemy ViewORM extends SQLAlchemy's ORM to provide a clean, Pythonic interface for creating and managing database views. It supports:

  • Standard views: Traditional simple SQL views that execute their query on each access
  • Materialized views: Views that store their results physically for faster access
  • Table-simulated views: For databases that don't support views or materialized views
  • Cross-database compatibility: Works with PostgreSQL, MySQL, SQLite, and more
  • Materialized view emulation: for DBMSs without materialized views support like SQLite, you can choose what method to use for each model: treat as a simple view or mock by a regular table – useful for tests.
  • Dialect-aware features: Allows views' queries customisation for each database
  • Type annotations: Fully typed with mypy support.

Well, I developed the lib for my own needs, because lots of other implementations that I found look too weak, and I strive for flexibility with comprehensive features.

Installation

pip install SQLAlchemy-ViewORM

Quick Example

from sqlalchemy import Column, Integer, String, Boolean, select
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy_view_orm import ViewBase, ViewConfig

# Regular SQLAlchemy model
class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)
    active = Column(Boolean, default=True)

# Define a view based on the User model
class ActiveUserView(ViewBase):
    __tablename__ = "active_users_view"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)

    # Define view configuration
    __view_config__ = ViewConfig(

        # Define the view's query
        definition=select(
            User.id, User.name, User.email
        ).where(User.active == True),

        # Create as materialized view for better performance
        materialized=True,

        # Enable concurrent refresh (PostgreSQL)
        concurrently=True
    )

# Create the view in the database
engine = create_engine("postgresql://user:pass@localhost/dbname")
ActiveUserView.metadata.create_all(engine)

# Refresh materialized view data
with engine.begin() as conn:
    for cmd in ActiveUserView.get_refresh_cmds(engine):
        conn.execute(cmd)

Features

View Types

  • Simple Views: Standard non-materialized views.

    __view_config__ = ViewConfig(
        definition=my_select_query,
        materialized=False  # Default
    )
    
  • Materialized Views: Physically stored query results, in DBMSs that supported materialized views (e.g. PostgreSQL and Oracle), and simple views are used in other cases.

    __view_config__ = ViewConfig(
        definition=my_select_query,
        materialized=True
    )
    
  • Table Views: For databases without native materialized view support (like SQLite, MySQL), you easily can emulate them with tables.

    __view_config__ = ViewConfig(
        definition=my_select_query,
        materialized=True,
        materialized_as_table=True  # Use tables to simulate materialized views
    )
    

Which is pretty helpful when developing apps for Postgres while testing with SQLite. Frankly speaking, this is why I developed the lib 🙂

Advanced Usage

Define views with dynamic queries to adjust by considering database dialect:

def build_query(dialect):
    # Adapt the query based on the database dialect
    if dialect == 'postgresql':
        return select(User.id, func.lower(User.email).label('email'))
    else:
        # Simpler version for other databases
        return select(User.id, User.email)

class UserEmailView(ViewBase):
    __tablename__ = "user_email_view"

    id = Column(Integer, primary_key=True)
    email = Column(String)

    __view_config__ = ViewConfig(
        definer=build_query,  # Pass a function instead of a fixed query
        materialized=True
    )

Why Use SQLAlchemy ViewORM?

Database views offer numerous advantages:

  1. Abstraction: Hide complex queries behind simple interfaces
  2. Performance: Materialized views improve query speed for complex calculations
  3. Consistency: Ensure the same ORM-based query logic is used across your application
  4. Security: Restrict access to sensitive data

This library makes it easy to leverage these benefits within your SQLAlchemy applications.

Documentation

For complete documentation, examples, and API reference, visit: https://github.com/AivanF/SQLAlchemy-ViewORM/docs

Project Status

This project is in passive development. We welcome contributions, bug reports, and feature requests, especially with suggested solutions. See CONTRIBUTING.md for details on how to contribute.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Full documentation is available in the docs directory.

Examples

Check out the examples directory for complete working code:

  • basic_example.py: Simple view usage with SQLite
  • advanced_example.py: Complex views with dialect-specific features
  • flask_example.py: Integration with Flask web applications
  • FastAPI-example/: Deeper example with async FastAPI web applications and updates

Running Tests

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# With coverage
pytest --cov=sqlalchemy_view_orm

Author

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

sqlalchemy_vieworm-0.1.1.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

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

sqlalchemy_vieworm-0.1.1-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file sqlalchemy_vieworm-0.1.1.tar.gz.

File metadata

  • Download URL: sqlalchemy_vieworm-0.1.1.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.20

File hashes

Hashes for sqlalchemy_vieworm-0.1.1.tar.gz
Algorithm Hash digest
SHA256 1d91b9283e127dc550ae04753161e88841efeb621a40841e143cd197c2c0ac2a
MD5 8c4fe08bd0179421e479c581140d7b4e
BLAKE2b-256 fe64c5d8273067faccead832096bd06b617ef803cf9e44bcd8c3830720b18d96

See more details on using hashes here.

File details

Details for the file sqlalchemy_vieworm-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for sqlalchemy_vieworm-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 732fc4700e651ba94418c7c2ce618683d1081d9ced42a6d68f8e71c74e3dac83
MD5 9d88b1008f7f1f997e5d601353ca911c
BLAKE2b-256 04c68be317f8bb373f541fcf776e5d95a1cd78ad2968a84fee5e2aef9a24366d

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