Home

Awesome

Saffier

<p align="center"> <a href="https://saffier.tarsild.io"><img src="https://res.cloudinary.com/dymmond/image/upload/v1675104815/Saffier/logo/logo_dowatx.png" alt='Saffier'></a> </p> <p align="center"> <em>🚀 The only Async ORM you need. 🚀</em> </p> <p align="center"> <a href="https://github.com/tarsil/saffier/workflows/Test%20Suite/badge.svg?event=push&branch=main" target="_blank"> <img src="https://github.com/tarsil/saffier/workflows/Test%20Suite/badge.svg?event=push&branch=main" alt="Test Suite"> </a> <a href="https://pypi.org/project/saffier" target="_blank"> <img src="https://img.shields.io/pypi/v/saffier?color=%2334D058&label=pypi%20package" alt="Package version"> </a> <a href="https://pypi.org/project/saffier" target="_blank"> <img src="https://img.shields.io/pypi/pyversions/saffier.svg?color=%2334D058" alt="Supported Python versions"> </a> </p>

Documentation: https://saffier.tarsild.io 📚

Source Code: https://github.com/tarsil/saffier


Announcement

Saffier is and always will be free and belongs to the community but due to the advancement of the Dymmond ecosystem, it was decided to persue the continuation of a more customisable, versatile, modular and faster tool to maintain and grow, Edgy. This does not mean Saffier will be forgotte, quite the opposite but the main efforts are focused on the open source of the ecosystem of Dymmond as there is a lot of work to carry on and the community is driven by that.

If you would like to continue with Saffier and also maintain it, I'm more than happy to pass it on to you as Saffier can grow in so many other possible ways that we can't even quantify it here.

Motivation

Almost every project, in one way or another uses one (or many) databases. An ORM is simply an mapping of the top of an existing database. ORM extends for Object Relational Mapping and bridges object-oriented programs and relational databases.

Two of the most well known ORMs are from Django and SQLAlchemy. Both have their own strengths and weaknesses and specific use cases.

This ORM is built on the top of SQLAlchemy core and aims to simplify the way the setup and queries are done into a more common and familiar interface.

Before continuing

If you are looking for something more Pydantic oriented where you can take literally advantage of everything that Pydantic can offer, then instead of continuing with Saffier, have a look at its data ORM brother, Edgy.

Edgy its extremely powerful as well with a key difference that its 100% Pydantic which means you can leverage the technology if you already familiar with it.

No worries, it is not completely different from Saffier, in fact, it was designed with the same principles and what it changes for you are essentially the imports.

Thinking of moving to Edgy?

If you are considering of moving to Edgy but you don't want to be bothered about learning a new tool and afraid of breaking changes, then fear not!

Edgy was designed to also make your migration feel seemless, which means that essentially you would only need to install it and change the imports in your project from saffier to edgy and it should work automatically for you.

Even the documentation structure its almost the same, intentionally, so what you already know with Saffier, you will know with Edgy.

This discards any custom code done by you, of course.

Why this ORM

When investigating for a project different types of ORMs and compared them to each other, for a lot of use cases, SQLAlchemyalways took the win but had an issue, the async support (which now there are a few solutions). While doing the research I came across Encode ORM.

The team is the same behind of Databases, Django Rest Framework, Starlette, httpx and a lot more tools used by millions.

There was one issue though, although ORM was doing a great familiar interface with SQLAlchemy and providing the async solution needed, it was, by the time of this writing, incomplete and they even stated that in the documentation and that is how Saffier was born.

Saffier uses some of the same concepts of ORM from Encode but rewritten in Pydantic but not all.

Saffier

Saffier is some sort of a fork from Encode ORM but rewritten at its core and with a complete set of tools with a familiar interface to work with. If you are familiar with Django, then you came for a treat 😄.

Saffier leverages the power of Pydantic for its fields while offering a friendly, familiar and easy to use interface.

This ORM was designed to be flexible and compatible with pretty much every ASGI framework, like Esmerald, Starlette, FastAPI, Sanic, Quart... With simple pluggable design thanks to its origins.

Special notes

Saffier couldn't exist without Encode ORM and the continous work done by the amazing team behind it. For that reason, thank you!

Features

While adopting a familiar interface, it offers some cool and powerful features on the top of SQLAlchemy core.

Key features

And a lot more you can do here.

Migrations

Since Saffier, like Encode ORM, is built on the top of SQLAlchemy core, it brings its own native migration system running on the top of Alembic but making it a lot easier to use and more pleasant for you.

Have a look at the migrations for more details.

Installation

To install Saffier, simply run:

$ pip install saffier

You can pickup your favourite database driver by yourself or you can run:

Postgres

$ pip install saffier[postgres]

MySQL/MariaDB

$ pip install saffier[mysql]

SQLite

$ pip install saffier[sqlite]

Quick Start

The following is an example how to start with Saffier and more details and examples can be found throughout the documentation.

Use ipython to run the following from the console, since it supports await.

import saffier
from saffier import Database, Registry

database = Database("sqlite:///db.sqlite")
models = Registry(database=database)


class User(saffier.Model):
    """
    The User model to be created in the database as a table
    If no name is provided the in Meta class, it will generate
    a "users" table for you.
    """

    id = saffier.IntegerField(primary_key=True)
    is_active = saffier.BooleanField(default=False)

    class Meta:
        registry = models


# Create the db and tables
# Don't use this in production! Use Alembic or any tool to manage
# The migrations for you
await models.create_all()

await User.query.create(is_active=False)

user = await User.query.get(id=1)
print(user)
# User(id=1)

As stated in the example, if no tablename is provided in the Meta class, Saffier automatically generates the name of the table for you by pluralising the class name.

Connect your application

Do you want to have more complex structures and connect to your favourite framework? Have a look at connections to understand how to do it properly.

Exciting!

In the documentation we go deeper in explanations and examples, this was just to warm up. 😁