Skip to content

How to use EncryptedType of SQLAlchemy #447

Open
@ChuckMoe

Description

@ChuckMoe

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the SQLModel documentation, with the integrated search.
  • I already searched in Google "How to X in SQLModel" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to SQLModel but to Pydantic.
  • I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

import os
from typing import Optional

import sqlalchemy
from sqlalchemy import Column
from sqlalchemy_utils import EncryptedType
from sqlalchemy_utils.types.encrypted.encrypted_type import AesEngine
from sqlmodel import create_engine, Field, Session, SQLModel


# https://sqlalchemy-utils.readthedocs.io/en/latest/_modules/sqlalchemy_utils/types/encrypted/encrypted_type.html#EncryptedType
class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    # Because the secret name should stay a secret
    secret_name: str = Field(
            sa_column=Column(
                    EncryptedType(
                            sqlalchemy.Unicode,
                            os.getenv('ENCRYPTION_KEY'),
                            AesEngine,
                            'pkcs5'
                            )
                    )
            )
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")  #
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")  #
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)  #

    print("Before interacting with the database")  #
    print("Hero 1:", hero_1)  #
    print("Hero 2:", hero_2)  #
    print("Hero 3:", hero_3)  #

    with Session(engine) as session:  #
        session.add(hero_1)  #
        session.add(hero_2)  #
        session.add(hero_3)  #

        print("After adding to the session")  #
        print("Hero 1:", hero_1)  #
        print("Hero 2:", hero_2)  #
        print("Hero 3:", hero_3)  #

        session.commit()  #

        print("After committing the session")  #
        print("Hero 1:", hero_1)  #
        print("Hero 2:", hero_2)  #
        print("Hero 3:", hero_3)  #

        print("After committing the session, show IDs")  #
        print("Hero 1 ID:", hero_1.id)  #
        print("Hero 2 ID:", hero_2.id)  #
        print("Hero 3 ID:", hero_3.id)  #

        print("After committing the session, show names")  #
        print("Hero 1 name:", hero_1.name)  #
        print("Hero 2 name:", hero_2.name)  #
        print("Hero 3 name:", hero_3.name)  #

        session.refresh(hero_1)  #
        session.refresh(hero_2)  #
        session.refresh(hero_3)  #

        print("After refreshing the heroes")  #
        print("Hero 1:", hero_1)  #
        print("Hero 2:", hero_2)  #
        print("Hero 3:", hero_3)  #
    #

    print("After the session closes")  #
    print("Hero 1:", hero_1)  #
    print("Hero 2:", hero_2)  #
    print("Hero 3:", hero_3)  #


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Description

This code is already working as is!

I did not find a tutorial for SLQModel on how to encrypt / decrypt data. I also thought of opening a PR to add this to the docu but as this approach uses a separate package (sqlalchemy_utils) for the column type EncryptedType I wanted to ask beforehand if that is wanted.

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.8

Python Version

3.10.4

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions