GithubHelp home page GithubHelp logo

tiangolo / sqlmodel Goto Github PK

View Code? Open in Web Editor NEW
13.0K 152.0 580.0 4.67 MB

SQL databases in Python, designed for simplicity, compatibility, and robustness.

Home Page: https://sqlmodel.tiangolo.com/

License: MIT License

Python 99.24% Shell 0.06% Jinja 0.69%
python sql sqlalchemy pydantic fastapi json json-schema

sqlmodel's Introduction

SQLModel

SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.

Test Publish Coverage Package version


Documentation: https://sqlmodel.tiangolo.com

Source Code: https://github.com/tiangolo/sqlmodel


SQLModel is a library for interacting with SQL databases from Python code, with Python objects. It is designed to be intuitive, easy to use, highly compatible, and robust.

SQLModel is based on Python type annotations, and powered by Pydantic and SQLAlchemy.

The key features are:

  • Intuitive to write: Great editor support. Completion everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.
  • Easy to use: It has sensible defaults and does a lot of work underneath to simplify the code you write.
  • Compatible: It is designed to be compatible with FastAPI, Pydantic, and SQLAlchemy.
  • Extensible: You have all the power of SQLAlchemy and Pydantic underneath.
  • Short: Minimize code duplication. A single type annotation does a lot of work. No need to duplicate models in SQLAlchemy and Pydantic.

Sponsors

SQL Databases in FastAPI

SQLModel is designed to simplify interacting with SQL databases in FastAPI applications, it was created by the same author. ๐Ÿ˜

It combines SQLAlchemy and Pydantic and tries to simplify the code you write as much as possible, allowing you to reduce the code duplication to a minimum, but while getting the best developer experience possible.

SQLModel is, in fact, a thin layer on top of Pydantic and SQLAlchemy, carefully designed to be compatible with both.

Requirements

A recent and currently supported version of Python.

As SQLModel is based on Pydantic and SQLAlchemy, it requires them. They will be automatically installed when you install SQLModel.

Installation

$ pip install sqlmodel
---> 100%
Successfully installed sqlmodel

Example

For an introduction to databases, SQL, and everything else, see the SQLModel documentation.

Here's a quick example. โœจ

A SQL Table

Imagine you have a SQL table called hero with:

  • id
  • name
  • secret_name
  • age

And you want it to have this data:

id name secret_name age
1 Deadpond Dive Wilson null
2 Spider-Boy Pedro Parqueador null
3 Rusty-Man Tommy Sharp 48

Create a SQLModel Model

Then you could create a SQLModel model like this:

from typing import Optional

from sqlmodel import Field, SQLModel


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

That class Hero is a SQLModel model, the equivalent of a SQL table in Python code.

And each of those class attributes is equivalent to each table column.

Create Rows

Then you could create each row of the table as an instance of the model:

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)

This way, you can use conventional Python code with classes and instances that represent tables and rows, and that way communicate with the SQL database.

Editor Support

Everything is designed for you to get the best developer experience possible, with the best editor support.

Including autocompletion:

And inline errors:

Write to the Database

You can learn a lot more about SQLModel by quickly following the tutorial, but if you need a taste right now of how to put all that together and save to the database, you can do this:

from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


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)


engine = create_engine("sqlite:///database.db")


SQLModel.metadata.create_all(engine)

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

That will save a SQLite database with the 3 heroes.

Select from the Database

Then you could write queries to select from that same database, for example with:

from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine, select


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


engine = create_engine("sqlite:///database.db")

with Session(engine) as session:
    statement = select(Hero).where(Hero.name == "Spider-Boy")
    hero = session.exec(statement).first()
    print(hero)

Editor Support Everywhere

SQLModel was carefully designed to give you the best developer experience and editor support, even after selecting data from the database:

SQLAlchemy and Pydantic

That class Hero is a SQLModel model.

But at the same time, โœจ it is a SQLAlchemy model โœจ. So, you can combine it and use it with other SQLAlchemy models, or you could easily migrate applications with SQLAlchemy to SQLModel.

And at the same time, โœจ it is also a Pydantic model โœจ. You can use inheritance with it to define all your data models while avoiding code duplication. That makes it very easy to use with FastAPI.

License

This project is licensed under the terms of the MIT license.

sqlmodel's People

Contributors

abenezerbelachew avatar alucarddelta avatar aminalaee avatar andrewbolster avatar batalex avatar bobronium avatar br-follow avatar byrman avatar chrisgoddard avatar chriswhite199 avatar cmarqu avatar daniil-berg avatar davidbrochart avatar ddanier avatar dependabot[bot] avatar dhiraj avatar egrim avatar elben10 avatar estebanx64 avatar fardad13 avatar feanil avatar hao-wang avatar jalvaradosegura avatar johnhoman avatar mr-drp avatar pre-commit-ci[bot] avatar rootux avatar tiangolo avatar van51 avatar zettzet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqlmodel's Issues

[Doc] Validation for adding documentation on how to use SQLModel with AsyncSession

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

from typing import Optional
from fastapi import FastAPI
from sqlmodel import Field, SQLModel, select
from sqlmodel.ext.asyncio.session import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine


sqlite_file_name = "database.db"
sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}"
connect_args = {"check_same_thread": False}
engine = create_async_engine(sqlite_url, future=True, echo=True, connect_args=connect_args)


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


app = FastAPI()


@app.on_event("startup")
async def startup():
    # create db tables
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.drop_all)
        await conn.run_sync(SQLModel.metadata.create_all)


@app.post("/heroes/")
async def create_hero(hero: Hero):
    async with AsyncSession(engine) as session:
        session.add(hero)
        await session.commit()
        await session.refresh(hero)
        return hero


@app.get("/heroes/")
async def read_heroes():
    async with AsyncSession(engine) as session:
        heroes = await session.exec(select(Hero))
        return heroes.all()

Description

What would be the best way to use async / await with the AsyncSession ?

I've implemented a first draft here :
fastapi-async-sqlmodel

But I feel like there is a better solution than using the aiosqlite driver.

If you think this is the proper way to use async / await, I will try to add it to the documentation.

Wanted Solution

I would like to add some documentation on how to use async / await with the SQLModel AsyncSession

Wanted Code

NA

Alternatives

No response

Operating System

Linux, Windows, macOS, Other

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.7.9

Additional Context

No response

Unsure how to specify foreign keys when receiving AmbiguousForeignKeysError

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

from typing import Optional
from uuid import uuid4

from sqlmodel import Field, Session, SQLModel, create_engine, Relationship

class Account(SQLModel, table=True):
    id: Optional[str] = Field(default=uuid4, primary_key=True)
    institution_id: str
    institution_name: str

class Transaction(SQLModel, table=True):
    id: Optional[str] = Field(default=uuid4, primary_key=True)
    from_account_id: Optional[str] = Field(default=None, foreign_key="account.id")
    from_account: Account = Relationship()
    to_account_id: Optional[str] = Field(default=None, foreign_key="account.id")
    to_account: Account = Relationship()
    amount: float

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

engine = create_engine(sqlite_url, echo=True)

SQLModel.metadata.create_all(engine)

account = Account(institution_id='1', institution_name='Account 1')

with Session(engine) as s:
    s.add(account)

Description

When creating a table with multiple relationships to another table I am receiving the AmbiguousForeignKeysError SQLAlchemy error. There doesn't appear to be a SQLModel argument for the foreign key on Relationship. I tried passing the following to SQLAlchemy using Relationship(sa_relationship_kwargs={'foreign_keys':...}), but neither are a SQLAlchemy Column

  • the SQLModel/pydantic field (a FieldInfo object)
  • that field's field_name.sa_column (a PydanticUndefined object at this point in initialization)

Not sure how else to pass the right foreign key (possibly using SQLAlchemy's Query API?). Hoping there's a cleaner SQLModel/pydantic way to do this!

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

3.9.5

Additional Context

Full stack trace:

2021-08-24 22:28:57,351 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2021-08-24 22:28:57,352 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("account")
2021-08-24 22:28:57,352 INFO sqlalchemy.engine.Engine [raw sql] ()
2021-08-24 22:28:57,352 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("transaction")
2021-08-24 22:28:57,352 INFO sqlalchemy.engine.Engine [raw sql] ()
2021-08-24 22:28:57,352 INFO sqlalchemy.engine.Engine COMMIT
Traceback (most recent call last):
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/relationships.py", line 2744, in _determine_joins
    self.primaryjoin = join_condition(
  File "<string>", line 2, in join_condition
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/sql/selectable.py", line 1184, in _join_condition
    cls._joincond_trim_constraints(
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/sql/selectable.py", line 1305, in _joincond_trim_constraints
    raise exc.AmbiguousForeignKeysError(
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'transaction' and 'account'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/trippwickersham/Projects/village/gh_issue.py", line 27, in <module>
    account = Account(institution_id='1', institution_name='Account 1')
  File "<string>", line 4, in __init__
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/state.py", line 474, in _initialize_instance
    manager.dispatch.init(self, args, kwargs)
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/event/attr.py", line 343, in __call__
    fn(*args, **kw)
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/mapper.py", line 3565, in _event_on_init
    instrumenting_mapper._check_configure()
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/mapper.py", line 1873, in _check_configure
    _configure_registries({self.registry}, cascade=True)
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/mapper.py", line 3380, in _configure_registries
    _do_configure_registries(registries, cascade)
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/mapper.py", line 3419, in _do_configure_registries
    mapper._post_configure_properties()
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/mapper.py", line 1890, in _post_configure_properties
    prop.init()
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/interfaces.py", line 222, in init
    self.do_init()
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/relationships.py", line 2142, in do_init
    self._setup_join_conditions()
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/relationships.py", line 2238, in _setup_join_conditions
    self._join_condition = jc = JoinCondition(
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/relationships.py", line 2633, in __init__
    self._determine_joins()
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/orm/relationships.py", line 2796, in _determine_joins
    util.raise_(
  File "/Users/trippwickersham/opt/miniconda3/envs/village/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Transaction.from_account - there are multiple foreign key paths linking the tables.  Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

Add sessionmaker

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

Session = sessionmaker(engine)

Description

Add an sqlalchemy compatible sessionmaker that generates SqlModel sessions

Wanted Solution

I would like to have a working sessionmaker

Wanted Code

from sqlmodel import sessionmaker

Alternatives

No response

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.6

Additional Context

No response

Is dynamic schema supported like in SQLAlchemy?

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

Example code from the blog:

Base = declarative_base()

class MyTableClass(Base):
	__tablename__ = 'myTableName'
	myFirstCol = Column(Integer, primary_key=True)
	mySecondCol = Column(Integer, primary_key=True)


Base.metadata.create_table(engine)

attr_dict = {'__tablename__': 'myTableName',
	     'myFirstCol': Column(Integer, primary_key=True),
	     'mySecondCol': Column(Integer)}

Description

I am looking if SQLModel supports dynamic schema like SQLAlchemy does. Example: https://sparrigan.github.io/sql/sqla/2016/01/03/dynamic-tables.html

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.0

Additional Context

No response

Question: is upsert possible with this library.

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

from typing import Optional

from sqlmodel import Field, SQLModel


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str

hero_1 = Hero(id=7, name="Deadpond", secret_name="Dive Wilson")

Description

Let say I have an instance of a model

I want to upsert hero_1 into the database: insert if this id does not exist yet, otherwise update. Is there a pattern to do that?

Operating System

Linux, macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.6

Additional Context

No response

Can SQLModel be more generic in its implementations? Swappable backends?

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 ๐Ÿ‘†

Description

SQLModel has emerged as the long-awaited missing link that uses type annotations to build generic data models to bridge the gap between data validators (like Pydantic) and ORM layer (like SQLAlchemy).

However at the moment SQLModel is tied directly to Pydantic and SQLAlchemy, and works only with Pydantic and SQLAlchemy.

I wonder if SQLModel can be a more generic bridge, to be used between any modern data validator, and ORM.

Wanted Solution

I'd like a stand-alone version of SQLModel that can be installed without requiring Pydantic and SQLModel to be installed along with it.

Operating System

Linux

Operating System Details

N/A

SQLModel Version

0.0.4

Python Version

3.8

Additional Context

No response

__fields_set__ incorrectly set unless using the validate class method

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

from sqlmodel import SQLModel
from typing import Optional
class HeroUpdate(SQLModel):
    name: Optional[str] = None
    secret_name: Optional[str] = None
    age: Optional[int] = None
hero = HeroUpdate(age=42)
print(hero.dict(exclude_unset=True))
# output = {'name': None, 'secret_name': None, 'age': 42}

Description

*Create a HeroUpdate model
*Create a HeroUpdate instance with unset fields
*Use the .dict attribute with the unset_fields parameter
*unset_fields show up as None rather than not being included in the dictionary
*works fine with Pydantic BaseModel instances

Operating System

macOS

Operating System Details

No response

SQLModel Version

'0.0.4'

Python Version

3.9.0

Additional Context

If it is run as:
hero = HeroUpdate.validate({'age':42})
the _fields_set_ are correctly set and it works

How to add sqlalchemy functional indexes to columns?

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

# How to do the SQLModel equivalent of:
from sqlalchemy import func, Index

Index('someindex', func.lower(mytable.c.somecol))

Description

How to add functional indexes to a table?

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

3.8.11

Additional Context

No response

async - can't access parent.child item (relationship models) using async

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 ๐Ÿ‘†

Dependencies:
aiosqlite
https://pypi.org/project/aiosqlite/

Example Code

import asyncio
from sqlmodel.ext.asyncio.session import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from typing import List, Optional
from sqlmodel import Field, Relationship, SQLModel, select


class Team(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    headquarters: str

    heroes: List["Hero"] = Relationship(back_populates="team")


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

    team_id: Optional[int] = Field(default=None, foreign_key="team.id")
    team: Optional[Team] = Relationship(back_populates="heroes")


class Item(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str


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

engine = create_async_engine(sqlite_url, echo=True)


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

    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.drop_all)
        await conn.run_sync(SQLModel.metadata.create_all)


async def create_heroes():
    async with AsyncSession(engine) as session:
        team_preventers = Team(name="Preventers", headquarters="Sharp Tower")
        hero_deadpond = Hero(
            name="Deadpond", secret_name="Dive Wilson", team=team_preventers
        )

        session.add(hero_deadpond)
        await session.commit()
        await session.refresh(hero_deadpond)

        print(hero_deadpond)


async def select_heroes():
    async with AsyncSession(engine) as session:
        statement = select(Team).where(Team.name == "Preventers")
        result = await session.execute(statement)
        team_preventers = result.scalar()
        print(f"Preventers team: {team_preventers}")
        print(f"Preventers heroes: {team_preventers.heroes}")


async def main():
    await create_db_and_tables()
    await create_heroes()
    await select_heroes()

if __name__ == "__main__":
    asyncio.run(main())

Operating System

macOS

Operating System Details

Using a MacBook with macOS running FastAPI with docker.

SQLModel Version

0.0.4

Python Version

3.8.6

Additional Context

We have two models with a one to many relationship (Team -> Hero).
Using async / await AsyncSession , we are trying to access the parent's child ( {team_preventers.heroes} ) but this is causing the following exception :

sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_() here. Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/14/xd2s)
sys:1: RuntimeWarning: coroutine 'Connection.cursor' was never awaited

Full stacktrace
Traceback (most recent call last):
  File "async_test.py", line 74, in <module>
    asyncio.run(main())
  File "/usr/local/Cellar/[email protected]/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/local/Cellar/[email protected]/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "async_test.py", line 71, in main
    await select_heroes()
  File "async_test.py", line 65, in select_heroes
    print(f"Preventers heroes: {team_preventers.heroes}")
  File "/lib/python3.9/site-packages/sqlalchemy/orm/attributes.py", line 481, in __get__
    return self.impl.get(state, dict_)
  File "/lib/python3.9/site-packages/sqlalchemy/orm/attributes.py", line 926, in get
    value = self._fire_loader_callables(state, key, passive)
  File "/lib/python3.9/site-packages/sqlalchemy/orm/attributes.py", line 962, in _fire_loader_callables
    return self.callable_(state, passive)
  File "/lib/python3.9/site-packages/sqlalchemy/orm/strategies.py", line 892, in _load_for_state
    return self._emit_lazyload(
  File "/lib/python3.9/site-packages/sqlalchemy/orm/strategies.py", line 1028, in _emit_lazyload
    result = session.execute(
  File "/lib/python3.9/site-packages/sqlmodel/orm/session.py", line 101, in execute
    return super().execute(  # type: ignore
  File "/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 1689, in execute
    result = conn._execute_20(statement, params or {}, execution_options)
  File "/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1583, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/lib/python3.9/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1452, in _execute_clauseelement
    ret = self._execute_context(
  File "/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
    self._handle_dbapi_exception(
  File "/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1999, in _handle_dbapi_exception
    util.raise_(exc_info[1], with_traceback=exc_info[2])
  File "/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1771, in _execute_context
    self.dialect.do_execute(
  File "/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 717, in do_execute
    cursor.execute(statement, parameters)
  File "/lib/python3.9/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 99, in execute
    self._adapt_connection._handle_exception(error)
  File "/lib/python3.9/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 228, in _handle_exception
    raise error
  File "/lib/python3.9/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 76, in execute
    _cursor = self.await_(self._connection.cursor())
  File "/lib/python3.9/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 60, in await_only
    raise exc.MissingGreenlet(
sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_() here. Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/14/xd2s)
sys:1: RuntimeWarning: coroutine 'Connection.cursor' was never awaited

calling `sqlalchemy.orm.aliased` on inherited SQLModel throws exception `sqlalchemy.exc.NoInspectionAvailable: No inspection system is available for object of type <class 'sqlmodel.main.SQLModelMetaclass'>`

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

from sqlmodel import SQLModel, Field
from typing import Optional
from sqlalchemy.orm import aliased

class MyModel(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

class MyNextModel(MyModel):
    name: str = Field(default="marvin")

# works fine
aliased(MyModel, name="my_model_alias")
# throws exception
aliased(MyNextModel, name="my_next_model_alias")

Description

I would expect to be able to alias a SQLModel object that inherits from another SQLModel object.

Running the example code produces the following error

  File "alias_bug.py", line 14, in <module>
    aliased(MyNextModel, name="my_next_model_alias")
  File "/opt/homebrew/Caskroom/miniconda/base/envs/py38/lib/python3.8/site-packages/sqlalchemy/orm/util.py", line 1236, in aliased
    return AliasedClass(
  File "/opt/homebrew/Caskroom/miniconda/base/envs/py38/lib/python3.8/site-packages/sqlalchemy/orm/util.py", line 494, in __init__
    insp = inspection.inspect(mapped_class_or_ac)
  File "/opt/homebrew/Caskroom/miniconda/base/envs/py38/lib/python3.8/site-packages/sqlalchemy/inspection.py", line 71, in inspect
    raise exc.NoInspectionAvailable(
sqlalchemy.exc.NoInspectionAvailable: No inspection system is available for object of type <class 'sqlmodel.main.SQLModelMetaclass'>

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8

Additional Context

No response

Can't use set in model_obj.dict(exclude=...)

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

None

Description

(using google translate...)

In pydantic, the dict() function argument exclude supports set and dict.
However, it seems that the case of set is not available in sqlmodel.
That problem seems to be coming from _calculate_keys.
Is set explicitly unsupported? Or am I missing something?

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.6

Additional Context

No response

SQLModel doesn't raise ValidationError

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

from typing import Optional

from pydantic import BaseModel
from sqlmodel import Field, SQLModel

class User1(SQLModel, table=True):
    id: Optional[int] = Field(primary_key=True)
    name: str

class User2(BaseModel):
    name: str

User1()
User2()

Description

  • Create SQLModel
  • Create equivalent pydantic model
  • Create instance of SQLModel without providing required arguments
  • Create instance of pydantic model without providing required arguments

The pydantic model raises an ValidationError whereas the SQLModel doesn't raise a ValidationError even though an required argument is not provided. I would expect a ValidationError if not all required arguments is provided.

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

Python 3.8.5

Additional Context

No response

Where with multiple expressions - Can we use a dict ?

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

@api.get("/devices", response_model=schemas.DeviceDisplay)
def get_devices(os_type: Optional[schemas.OsTypes] = None,
                discovered: Optional[schemas.Discovered] = None,
                device_site: Optional[str]
                device_status: Optional[schemas.DevicesStatus]
                db: Session = Depends(dependencies.get_session),
                api_key: APIKey = Depends(dependencies.get_api_key)):
    filters_items = {}
    if os_type.value: filters_items['platform'] = os_type.value 
    if discovered.value: filters_items['discovered'] = discovered.value 
    if device_site: filters_items['site'] = device_site 
    if device_status: filters_items['status'] = device_status 
    statement = select(sql_models.devices).where(**filters_items)
    request_exec = db.exec(statement)
    result = request_exec.all()
    return result

Description

I'm using FastAPI and just installed SQLModel to test it.

For this use case (GET request), end user should be able to select one or multiple options which would be used to filter entries to return (Like Site or OS Type). Each field is optional, and I can't strictly determine/know in advance which item will have to be used as a WHERE CLAUSE.
In the same way, if end user let all field to Default (None/Null), the where clause will be used in the request, but with no filters.

So, as I'm doing with SQLAlchemy, I can create a dictionary and push it into my request, and it will automatically take the dictionary key and transform them in WHERE Clauses through the filter_by function.
But I didn't find a way to the same with SQLModel. it seems that we have to "statically" specify which items we want to use as filters.

Am I missing something ?
If not, how can we do the job with SQLModel ?

Here is the error message I have :
Exception:..... TypeError: where() got an unexpected keyword argument 'platform'
(Which seems to be normal, as we can't use keywords argument in a where, as explained in the documentation)

Thanks a lot for your support,

Operating System

Linux

Operating System Details

FastAPI runs into a Docker container.

SQLModel Version

0.0.3

Python Version

3.8.6

Additional Context

No response

Custom Root Types are detected as NullType by SQLAlchemy

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

from typing import Optional

from sqlmodel import Field, SQLModel, create_engine

class MyNewCustomRootType(SQLModel):
  __root__ : str

class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None
    my_new_attribute: MyNewCustomRootType 


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

engine = create_engine(sqlite_url, echo=True)

SQLModel.metadata.create_all(engine)

Description

  1. Add a type that uses the technique described in the Custom Root Types section of the Pydantic docs.
  2. Use this type for a type hint in a model that creates a SQLModel table.
  3. Run metadata creation.
  4. SQLAlchemy will error out claiming that you didn't set a type (but I did!)

This library looks really cool, but my Pydantic models use custom root types in a few places and if I can't use them I'll have to replicate a ton of code over and over again. Is this intentional behavior, or is it possible support for them can be added?

Operating System

Linux, macOS

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

3.9.4, 3.8

Additional Context

The full traceback from trying to run the example in a Repl.it instance:

2021-08-25 02:42:46,495 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2021-08-25 02:42:46,495 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("hero")
2021-08-25 02:42:46,495 INFO sqlalchemy.engine.Engine [raw sql] ()
2021-08-25 02:42:46,496 INFO sqlalchemy.engine.Engine PRAGMA temp.table_info("hero")
2021-08-25 02:42:46,496 INFO sqlalchemy.engine.Engine [raw sql] ()
2021-08-25 02:42:46,497 INFO sqlalchemy.engine.Engine ROLLBACK
Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4031, in visit_create_table
    processed = self.process(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 490, in process
    return obj._compiler_dispatch(self, **kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
    return meth(self, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4065, in visit_create_column
    text = self.get_column_specification(column, first_pk=first_pk)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/dialects/sqlite/base.py", line 1424, in get_column_specification
    coltype = self.dialect.type_compiler.process(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 522, in process
    return type_._compiler_dispatch(self, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
    return meth(self, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4612, in visit_null
    raise exc.CompileError(
sqlalchemy.exc.CompileError: Can't generate DDL for NullType(); did you forget to specify a type on this Column?

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "main.py", line 21, in <module>
    SQLModel.metadata.create_all(engine)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/schema.py", line 4739, in create_all
    bind._run_ddl_visitor(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/future/engine.py", line 342, in _run_ddl_visitor
    conn._run_ddl_visitor(visitorcallable, element, **kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2081, in _run_ddl_visitor
    visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 485, in traverse_single
    return meth(obj, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 846, in visit_metadata
    self.traverse_single(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 485, in traverse_single
    return meth(obj, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 890, in visit_table
    self.connection.execute(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/future/engine.py", line 280, in execute
    return self._execute_20(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1582, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 77, in _execute_on_connection
    return connection._execute_ddl(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1349, in _execute_ddl
    compiled = ddl.compile(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 517, in compile
    return self._compiler(dialect, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 29, in _compiler
    return dialect.ddl_compiler(dialect, self, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 455, in __init__
    self.string = self.process(self.statement, **compile_kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 490, in process
    return obj._compiler_dispatch(self, **kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
    return meth(self, **kw)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4041, in visit_create_table
    util.raise_(
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
sqlalchemy.exc.CompileError: (in table 'hero', column 'my_new_attribute'): Can't generate DDL for NullType(); did you forget to specify a type on this Column?

AsyncSession does not play well with typing and autocompletion

TL;DR: Fix is available here: #58, pls merge.

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 asyncio
from typing import Optional

from sqlalchemy.ext.asyncio import create_async_engine
from sqlmodel import Field, SQLModel, select
from sqlmodel.ext.asyncio.session import AsyncSession


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


async def main() -> None:
    engine = create_async_engine("sqlite+aiosqlite:///database.db")

    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)

    async with AsyncSession(engine) as session:
        session.add(Hero(name="Spider-Boy", secret_name="Pedro Parqueador"))
        await session.commit()

    async with AsyncSession(engine) as session:
        statement = select(Hero).where(Hero.name == "Spider-Boy")
        h = (await session.exec(statement)).first()
        print(h)  # name='Spider-Boy' id=2 age=None secret_name='Pedro Parqueador'


asyncio.run(main())

Description

First of all, props for yet another amazing library! ๐ŸŽ‰โค๏ธ

I didn't dive into source code yet to verify that I'm doing the right thing, but in the runtime the snippet behaves as expected. However that's not the case with static analysis:

  • Mypy gives this error:

    $ mypy model.py  # Mypy Version: 0.910                                        
    model.py:21: error: Argument 1 to "exec" of "AsyncSession" has incompatible type "SelectOfScalar[Hero]"; expected "Union[Select[<nothing>], Executable[<nothing>]]"
    Found 1 error in 1 file (checked 1 source file)
  • PyCharm fails to derive session variable type:
    image
    May be related to PY-29891!

  • Even when session type explicitly stated, PyCharm still struggles to provide same experience as with sync Session
    image

I acknowledge that the issue might be caused Typing/MyPy/PyCharm limitations.

I would be happy to work towards fixing the issue in my free time. Ideally, for that I'd want some clarification and thoughts regarding the issue.

Operating System

macOS 11.4 (20F71)

SQLModel Version

0.0.4

Python Version

Python 3.9.6

Additional Context

  • Before running code snipped, you need to pip install aiosqlite sqlalchemy[asyncio]
  • Mypy Version: 0.910
  • PyCharm Version: PyCharm 2021.1.3 (Professional Edition) Build #PY-211.7628.24, built on June 30, 2021

postgreSQL: SQLModel.metadata.create_all(engine) doesn't create the database file

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

from datetime import datetime
from typing import Optional, Dict
from sqlmodel import Field, SQLModel, create_engine

class SemanticSearch(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    id_user: int
    date_time: datetime
    query: str
    clean_query: str
    
engine = create_engine('postgresql://postgres:postgres@localhost:5432/embeddings_sts_tf', echo=True)

SQLModel.metadata.create_all(engine)

Description

Following the tutorial user guide based on sqlite I tried to do the same with postgresql database, but contrary to sqlite the SQLModel.metadata.create_all(engine) command doesn't seem to create my embeddings_sts_tf postgresql database

Operating System

Linux

Operating System Details

Ubuntu 18.04 LTS

SQLModel Version

0.0.4

Python Version

3.8.8

Additional Context

No response

How to deal with Postgres Enum columns?

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

from typing import List, Optional
from enum import Enum

import sqlalchemy as sa
import sqlmodel


class Status(str, Enum):
    active = "active"
    banned = "banned"


status_enum = postgresql.ENUM("active", "banned", "c", name="status_enum")


class User(sqlmodel.SQLModel, table=True):
    __tablename__ = "auth_user"
    id: int = sqlmodel.Field(primary_key=True)
    status: Status = sqlmodel.Field(status_enum)
    password: str

Description

How to use Postgres Enums together with SQLModel?

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

3.8.11

Additional Context

No response

sqlalchemy.exc.CompileError: Can't generate DDL for NullType(); did you forget to specify a type on this Column?

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

from datetime import datetime
from typing import Optional, List, Tuple, Dict, Union
from typing_extensions import TypedDict
from sqlmodel import Field, SQLModel, create_engine
from sqlalchemy_utils.functions import database_exists, create_database

class InnerSemanticSearchDict(TypedDict):
    acquis_code: str
    code: str
    level: int
    title: str
    similarity_score: float

class SemanticSearchDict(TypedDict):
    rank: int
    value: InnerSemanticSearchDict

class SemanticSearch(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    id_user: int
    date_time: datetime
    query: str
    clean_query: str
    semantic_search_result: List[SemanticSearchDict]

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

if not database_exists('postgresql://postgres:postgres@localhost:5432/embeddings_sts_tf'):
    create_database('postgresql://postgres:postgres@localhost:5432/embeddings_sts_tf')

engine = create_engine('postgresql://postgres:postgres@localhost:5432/embeddings_sts_tf', echo=True)

SQLModel.metadata.create_all(engine)

Description

I would like to create a semanticsearch table in the embeddings_sts_tf postgresql database with the 6 fields specified.

But I got the following error code:

2021-09-01 15:35:32,439 INFO sqlalchemy.engine.Engine select version()
2021-09-01 15:35:32,440 INFO sqlalchemy.engine.Engine [raw sql] {}
2021-09-01 15:35:32,440 INFO sqlalchemy.engine.Engine select current_schema()
2021-09-01 15:35:32,440 INFO sqlalchemy.engine.Engine [raw sql] {}
2021-09-01 15:35:32,441 INFO sqlalchemy.engine.Engine show standard_conforming_strings
2021-09-01 15:35:32,441 INFO sqlalchemy.engine.Engine [raw sql] {}
2021-09-01 15:35:32,441 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2021-09-01 15:35:32,442 INFO sqlalchemy.engine.Engine select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where pg_catalog.pg_table_is_visible(c.oid) and relname=%(name)s
2021-09-01 15:35:32,442 INFO sqlalchemy.engine.Engine [generated in 0.00015s] {'name': 'semanticsearch'}
2021-09-01 15:35:32,443 INFO sqlalchemy.engine.Engine ROLLBACK
Traceback (most recent call last):
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4143, in visit_create_table
    processed = self.process(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 489, in process
    return obj._compiler_dispatch(self, **kwargs)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 82, in _compiler_dispatch
    return meth(self, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4177, in visit_create_column
    text = self.get_column_specification(column, first_pk=first_pk)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/dialects/postgresql/base.py", line 2509, in get_column_specification
    colspec += " " + self.dialect.type_compiler.process(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 521, in process
    return type_._compiler_dispatch(self, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 82, in _compiler_dispatch
    return meth(self, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4724, in visit_null
    raise exc.CompileError(
sqlalchemy.exc.CompileError: Can't generate DDL for NullType(); did you forget to specify a type on this Column?

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/matthieu/Code/Python/fastapi-graphql/embeddings_sts_tf_postgresql_db.py", line 65, in <module>
    SQLModel.metadata.create_all(engine)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/schema.py", line 4740, in create_all
    bind._run_ddl_visitor(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/future/engine.py", line 342, in _run_ddl_visitor
    conn._run_ddl_visitor(visitorcallable, element, **kwargs)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2082, in _run_ddl_visitor
    visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 520, in traverse_single
    return meth(obj, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 846, in visit_metadata
    self.traverse_single(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 520, in traverse_single
    return meth(obj, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 890, in visit_table
    self.connection.execute(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/future/engine.py", line 280, in execute
    return self._execute_20(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1583, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 77, in _execute_on_connection
    return connection._execute_ddl(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1350, in _execute_ddl
    compiled = ddl.compile(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 489, in compile
    return self._compiler(dialect, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 29, in _compiler
    return dialect.ddl_compiler(dialect, self, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 454, in __init__
    self.string = self.process(self.statement, **compile_kwargs)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 489, in process
    return obj._compiler_dispatch(self, **kwargs)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 82, in _compiler_dispatch
    return meth(self, **kw)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/sql/compiler.py", line 4153, in visit_create_table
    util.raise_(
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
sqlalchemy.exc.CompileError: (in table 'semanticsearch', column 'semantic_search_result'): Can't generate DDL for NullType(); did you forget to specify a type on this Column?

Operating System

Linux

Operating System Details

Ubuntu 18.04 LTS

SQLModel Version

0.0.4

Python Version

3.8.8

Additional Context

No response

Switching postgres schema from client side for SaaS projects

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

Pass

Description

For SaaS we need solution to use different postgre sql schema. Different users have different tenant and have to switch schema on fly.

Wanted Solution

Is there any solution to switch schema based on passed information from client side? Such as we can send schema name through jwt.

Wanted Code

Pass

Alternatives

No response

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9

Additional Context

No response

Alembic Migration when going from SQLAlchemy declarative_base to SQLModel adding indexes

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

# Original SQLAlchamy Schema

import uuid

from sqlalchemy import Column, DateTime
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import declarative_base


Base = declarative_base()


class User(Base):
    __tablename__ = "user"
    id: uuid.UUID = Column(UUID(as_uuid=True), primary_key=True, unique=True, default=uuid.uuid4)
    created_at = Column(DateTime, nullable=False)
    updated_at = Column(DateTime, nullable=False)


# Updated to sqlmodel Schema

import uuid
from datetime import datetime

from sqlmodel import Field, SQLModel


class User(SQLModel, table=True):
    id: uuid.UUID = Field(primary_key=True, default=uuid.uuid4)
    created_at: datetime
    updated_at: datetime


# Resulting Auto Migration

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('user', 'id',
               existing_type=postgresql.UUID(),
               nullable=True)
    op.create_index(op.f('ix_user_created_at'), 'user', ['created_at'], unique=False)
    op.create_index(op.f('ix_user_id'), 'user', ['id'], unique=False)
    op.create_index(op.f('ix_user_updated_at'), 'user', ['updated_at'], unique=False)
    # ### end Alembic commands ###

Description

Using Postgres 13, alembic 1.6.5, and SQLAlchemy 1.4.22. All deps locked with poetry and run inside a docker container.

  • Create a simple auto migration with Alembic based on SQLAlchemy declarative_base models alembic revision --autogenerate
  • Upgrade DB with migration
  • Change schema to use sqlmodel and run automigration again.

The resulting migration includes a bunch of unnecessary indexes.

Operating System

Linux

Operating System Details

Ubuntu in Docker on Linux host

FROM python@sha256:8f642902ba368481c9aca0a100f08daf93793c6fa14d3002253ea3cd210383a7

SQLModel Version

0.0.3

Python Version

3.9.6

Additional Context

No response

How to use Mixins?

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

class TimeStampMixin:
    """Provides last created/modified timestamps"""

    created_at: Optional[datetime] = Field(
        sa_column=Column(
            DateTime,
            default=datetime.utcnow,
            nullable=False,
        )
    )

    updated_at: Optional[datetime] = Field(
        sa_column=Column(
            DateTime,
            default=datetime.utcnow,
            onupdate=datetime.utcnow,
        )
    )


class MyModel(SQLModel, TimestampMixin, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str

Description

  • Utilize mixins that don't necessarily need to subclass SQLModel
    • Perhaps something that resembles @declarative_mixin from SQLAlchemy?

The above example errors with:

AttributeError: type object 'TimeStampMixin' has no attribute '__config__'

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.0

Additional Context

No response

Non-optional property with default value is not translated to a non-nullable field in sqlalchemy

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

from typing import Optional
from sqlmodel import SQLModel, Field, create_engine


class Test(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    a: str
    b: Optional[str] = None
    c: str = Field(default="Hey")
    d: str = "hey"
    
sqlite_url = ""  # define a path here
engine = create_engine(sqlite_url, echo=True)
SQLModel.metadata.create_all(engine)

Description

The above code example issues the following create table sql command:

CREATE TABLE test (
	id INTEGER, 
	a VARCHAR NOT NULL, 
	b VARCHAR, 
	c VARCHAR, 
	d VARCHAR, 
	PRIMARY KEY (id)
)

whereas I would expect columns c and d to be marked as NOT NULL as well.
I think the documentation also points to my point of view as stated here.

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.5

Additional Context

No response

JSON Fields for Nested Pydantic Models?

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

from tortoise.models import Model 
from tortoise.fields import UUIDField, DatetimeField,CharField, BooleanField, JSONField, ForeignKeyField, CharEnumField, IntField
from tortoise.contrib.pydantic import pydantic_model_creator

class Schedule(Model):
    id = UUIDField(pk=True)
    created_at = DatetimeField(auto_now_add=True)
    modified_at = DatetimeField(auto_now=True)
    case = JSONField()
    type = CharEnumField(SchemasEnum,description='Schedule Types')
    username = ForeignKeyField('models.Username')
    description = CharField(100)
    
schedule_pydantic = pydantic_model_creator(Schedule,name='Schedule')

Description

I have already implemented an API using FastAPI to store Pydantic Models. These models are themselves nested Pydantic models so the way they interact with a Postgres DataBase is throught JsonField. I've been using Tortoise ORM as the example shows.

Is there an equivalent model in SQLModel?

Operating System

Linux

Operating System Details

WSL 2 Ubuntu 20.04

SQLModel Version

0.0.4

Python Version

3.8

Additional Context

No response

Unable to use pydantic validators on Relation attributes

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

from sqlmodel import Field, Relationship, SQLModel

class Address(SQLModel, table=True):
    id: Optional[int] = Field(primary_key=True)
    country: str
    city: str
    street: str
    street_number: int

class Building(SQLModel, table=True):
    id: int = Field(primary_key=True)
    address_id: int = Field(foreign_key=f"{ADDRESSES}.id")
    address: Address = Relationship()
    age: int

    class Config:
        arbitrary_types_allowed = True

    @validator('address', pre=True)
    def validate_address(cls, v):
        return Address.parse_obj(v)

# Importing Building produces the error "pydantic.errors.ConfigError: Validators defined with incorrect fields: validate_address (use check_fields=False if you're inheriting from the model and intended this)"

Description

I want to parse a Building instance from a nested dictionary d with the Building and Address class defined in the example code.

d = {
  'address': {
     'country': 'US',
     'city': 'New York',
     'street': 'Centre St',
     'street_num': 1},
   'age': 40
}

So far I have been unavailable to successfully execute Building.parse_obj(d). Commenting out the validator in Building solves the pydantic error bein raised but the address of the parsed building will be a dict instead of an Address instance

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.6.12

Additional Context

No response

Improper UUID serialisation dropping leading zeros โ–ถ๏ธ "ValueError: badly formed hexadecimal UUID string"

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 uuid
from typing import Optional

import sqlalchemy.exc
from sqlmodel import SQLModel, Field
from sqlmodel import create_engine, Session, select


class Hero(SQLModel, table=True):
    id: Optional[uuid.UUID] = Field(primary_key=True,
                                    default_factory=uuid.uuid4)
    name: str
    secret_name: str
    age: Optional[int] = None

    def __str__(self):
        return f'{self.name} (AKA {self.secret_name}) [{self.age if self.age is not None else "Unknown"}]'


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

engine = create_engine(sqlite_url, echo=True)  # remove echo for prod


def create_db_and_tables():
    try:
        Hero.__table__.drop(engine)
    except sqlalchemy.exc.OperationalError:  # table doesn't exist yet
        pass
    SQLModel.metadata.create_all(engine)


def create_heroes():
    heros = [
        Hero(name="Deadpond", secret_name="Dive Wilson"),
        Hero(name="Spider-Boy", secret_name="Pedro Parqueador"),
        Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48),
        Hero(name="Tarantula", secret_name="Natalia Roman-on", age=32),
        Hero(name="Black Lion", secret_name="Trevor Challa", age=35),
        Hero(name="Dr. Weird", secret_name="Steve Weird", age=36),
        Hero(name="Captain North America", secret_name="Esteban Rogelios", age=93),
    ]

    with Session(engine) as session:
        for hero in heros:
            session.add(hero)
        session.commit()


def select_heroes():
    with Session(engine) as session:
        for hero in session.exec(select(Hero)):
            print(hero.id)


if __name__ == "__main__":
    while True:
        try:
            create_db_and_tables()
            create_heroes()
            select_heroes()
        except ValueError:
            raise

Cleansed Traceback

Traceback (most recent call last):
  File โ€œ/โ€ฆ/sqlmodel_tutorial/minimal_example.py", line 89, in <module>
    select_heroes()
  File โ€œ/โ€ฆ/sqlmodel_tutorial/minimal_example.py", line 80, in select_heroes
    for hero in session.exec(select(Hero)):
  File "/.../lib/python3.8/site-packages/sqlalchemy/engine/result.py", line 381, in iterrows
    for row in self._fetchiter_impl():
  File "/.../lib/python3.8/site-packages/sqlalchemy/orm/loading.py", line 147, in chunks
    fetch = cursor._raw_all_rows()
  File "/.../lib/python3.8/site-packages/sqlalchemy/engine/result.py", line 392, in _raw_all_rows
    return [make_row(row) for row in rows]
  File "/.../lib/python3.8/site-packages/sqlalchemy/engine/result.py", line 392, in <listcomp>
    return [make_row(row) for row in rows]
  File "/.../lib/python3.8/site-packages/sqlalchemy/sql/type_api.py", line 1430, in process
    return process_value(value, dialect)
  File "/.../lib/python3.8/site-packages/sqlmodel/sql/sqltypes.py", line 61, in process_result_value
    value = uuid.UUID(value)
  File โ€œ/โ€ฆ/lib/python3.8/uuid.py", line 171, in __init__
    raise ValueError('badly formed hexadecimal UUID string')
ValueError: badly formed hexadecimal UUID string

Description

Running through the tutorial up until around this point, I tried swapping out the int id key for a UUID key.

This works except whenever the uuid.uuid4 default factory creates a UUID with a hexstring that starts with a zero.

It appears that here in sqltypes.py that, rather than using UUID().hex, sqltypes.py carries on sqlalchemy's integer stringification apprach, however, doesn't include any padding declaration.

IMO there are two options;

  1. faithfully fix the replication of SQLAlchemy's UUID โ–ถ๏ธ int โ–ถ๏ธ str approach with the padding fixed (f"{v.int:032x}")
  2. switch to using the stdlib UUID.hex implementation for serialisation

Personally I'm a fan of the latter so will spin up a PR

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.8

Additional Context

No response

Implementation for no sql

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

no code

Description

sql is good but do you know any implemention for no sql ??!

Wanted Solution

no code

Wanted Code

no code

Alternatives

No response

Operating System

Linux, Windows, macOS, Other

Operating System Details

No response

SQLModel Version

no version

Python Version

any version

Additional Context

No response

How to define unique constraint in table columns

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

class User(SQLModel, table=True):
    user_uuid: UUID = Field(default=uuid4, primary_key=True)
    name: str
    email: str
    password: str
    balance: float = Field(default=0.0)
    income: float = Field(default=0.0)

Description

Hi, guys!

I want to define something like:
email: str = Field(unique=True)

But Field does not have unique param, like SQLAlchemy Column have:
Column(unique=True)

I've searched in Docs, Google and GitHub, but I found nothing about unique constraint.

Thanks for your attention!

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.4

Additional Context

No response

How to access a parent model's relationship's attributes

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

class UserBase(Base):
    username: str
    in_game_name: str
    discord_name: Optional[str] = Field(default=None)
    is_active: Optional[bool] = Field(default=True)
    is_superuser: Optional[bool] = Field(default=False)

    company: Optional[CompanyUser] = Relationship(back_populates="company")


class UserRead(UserBase):
    rank: str = UserBase.company.rank

---------
class CompanyUser(SQLModel, table=True):
    """
    Link Table to store ranks between users and a company
    """

    company_id: uuid.UUID = Field(foreign_key="company.id", primary_key=True)
    user_id: uuid.UUID = Field(foreign_key="user.id", primary_key=True)

    rank: str

    company: "CompanyBase" = Relationship(back_populates="members")
    user: "UserBase" = Relationship(back_populates="company")


class CompanyBase(Base):
    name: str
    logo_id: Optional[uuid.UUID] = Field(default=None, foreign_key="file.id")

    members: List[CompanyUser] = Relationship(back_populates="user")

Description

Erroring on UserRead>rank: UserBase has no attribute "company".

Effectively, I'm unsure how to access the parent model's relationships.

Operating System

Linux, Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.7

Additional Context

Trying to follow this guide on link tables with attributes: https://sqlmodel.tiangolo.com/tutorial/many-to-many/link-with-extra-fields/

Add support for Decimal in Pydantic and SQLAlchemy

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

class City(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)  # pylint: disable=invalid-name
    name: str = Field(nullable=False, max_length=150, index=False)
    population: Optional[int] = Field(default=None, index=False)
    latitude: condecimal(max_digits=13, decimal_places=10) = Field(nullable=False, index=False)
    longitude: condecimal(max_digits=13, decimal_places=10) = Field(nullable=False, index=False)

Description

When setting max_digits and decimal_places to condecimal these are ignored.
The SQL CREATE TABLE resulting from the previous model city definition results in:

CREATE TABLE city (
	id INTEGER AUTO_INCREMENT, 
	name VARCHAR(150) NOT NULL, 
	population INTEGER, 
	latitude NUMERIC NOT NULL, 
	longitude NUMERIC NOT NULL, 
	PRIMARY KEY (id)
)

So latitude and longitude are created with default parameters max_digits = 10 and decimal_places = 0.

Operating System

Linux

Operating System Details

Ubuntu 18.04

SQLModel Version

0.0.4

Python Version

3.7.11

Additional Context

This is my requirements.txt:

fastapi==0.68.1
uvicorn==0.15.0
python-multipart==0.0.5
pydantic==1.8.2
pymysql==1.0.2
python-jose[cryptography]
passlib
starlette-json
bcrypt
sqlmodel==0.0.4

How to run a database migration when using SQLModel (such as Alembic)?

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

I created a simple app (based on the documentation using FastAPI and SQLModel)
This can be run with either Docker or a python virtual environment, to speed things up.

https://github.com/joemudryk/learning-sqlmodel

Description

I am trying to:

  1. Create a database from the existing model
  2. Update the model (or uncomment this line )
  3. Run a database migration such as Alembic
  4. Continue to use the application with the updated model and database

Any help would be greatly appreciated, and maybe the instructions can be used to help update the official documentation :)

Operating System

Linux

Operating System Details

Linux Mint 20.1

SQLModel Version

0.0.4

Python Version

3.9.6

Additional Context

I was able to use Alembic for the orm library ormar okay. The instructions for that can be found here:
https://collerek.github.io/ormar/models/migrations/

Maybe that will give some insight for the approach I took, or you will find a solution that I didn't.

Thank you in advanced.

Convert all fields to optional

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

class HeroBase(SQLModel):
    name: str
    secret_name: str
    age: Optional[int] = None

class HeroUpdate(HeroBase, all_optional=True):
    pass

Description

Is it possible to add the ability to modify the fields of a base class to convert them to all optional with a parameter like the table=True but in this case all_optional=True? This would help eliminate the duplication when creating a class for making updates.

Wanted Solution

Set all base fields to Optional based on keyword argument.

Wanted Code

class HeroBase(SQLModel):
    name: str
    secret_name: str
    age: Optional[int] = None

class HeroUpdate(HeroBase, all_optional=True):
    pass

Alternatives

No response

Operating System

Linux, Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.5

Additional Context

No response

ERROR: Could not find a version that matches sqlalchemy2-stubs

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

% pipenv install
Pipfile.lock (16c839) out of date, updating to (2bfea0)...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
โœ˜ Locking Failed! 
[ResolutionFailure]:   File "/usr/local/Cellar/pipenv/2021.5.29/libexec/lib/python3.9/site-packages/pipenv/resolver.py", line 741, in _main
[ResolutionFailure]:       resolve_packages(pre, clear, verbose, system, write, requirements_dir, packages, dev)
[ResolutionFailure]:   File "/usr/local/Cellar/pipenv/2021.5.29/libexec/lib/python3.9/site-packages/pipenv/resolver.py", line 702, in resolve_packages
[ResolutionFailure]:       results, resolver = resolve(
[ResolutionFailure]:   File "/usr/local/Cellar/pipenv/2021.5.29/libexec/lib/python3.9/site-packages/pipenv/resolver.py", line 684, in resolve
[ResolutionFailure]:       return resolve_deps(
[ResolutionFailure]:   File "/usr/local/Cellar/pipenv/2021.5.29/libexec/lib/python3.9/site-packages/pipenv/utils.py", line 1397, in resolve_deps
[ResolutionFailure]:       results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
[ResolutionFailure]:   File "/usr/local/Cellar/pipenv/2021.5.29/libexec/lib/python3.9/site-packages/pipenv/utils.py", line 1110, in actually_resolve_deps
[ResolutionFailure]:       resolver.resolve()
[ResolutionFailure]:   File "/usr/local/Cellar/pipenv/2021.5.29/libexec/lib/python3.9/site-packages/pipenv/utils.py", line 835, in resolve
[ResolutionFailure]:       raise ResolutionFailure(message=str(e))
[pipenv.exceptions.ResolutionFailure]: Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies.
  First try clearing your dependency cache with $ pipenv lock --clear, then try the original command again.
 Alternatively, you can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation.
  Hint: try $ pipenv lock --pre if it is a pre-release dependency.
ERROR: Could not find a version that matches sqlalchemy2-stubs (from sqlmodel==0.0.4->-r /var/folders/_d/pcm157vn4kg3mv8wvb37vy2w0000gn/T/pipenva49pmcxnrequirements/pipenv-qf_w3zcm-constraints.txt (line 2))
Skipped pre-versions: 0.0.1a1, 0.0.1a2, 0.0.1a3, 0.0.1a4, 0.0.1a4, 0.0.1a5, 0.0.1a5, 0.0.1a6, 0.0.1a6, 0.0.1a7, 0.0.1a7, 0.0.1a8, 0.0.1a8, 0.0.1a9, 0.0.1a9, 0.0.1a10, 0.0.1a10, 0.0.1a11, 0.0.1a11, 0.0.2a1, 0.0.2a1, 0.0.2a2, 0.0.2a2, 0.0.2a3, 0.0.2a3, 0.0.2a4, 0.0.2a4, 0.0.2a5, 0.0.2a5, 0.0.2a6, 0.0.2a6, 0.0.2a7, 0.0.2a7, 0.0.2a8, 0.0.2a8, 0.0.2a9, 0.0.2a9, 0.0.2a10, 0.0.2a10, 0.0.2a11, 0.0.2a11, 0.0.2a12, 0.0.2a12
There are incompatible versions in the resolved dependencies:

Description

from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine, select


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


engine = create_engine("sqlite:///database.db")


with Session(engine) as session:

    statement = select(Hero).where(Hero.name == "Spider-Boy")

    hero = session.exec(statement).first()

    print(hero)

Operating System

macOS

Operating System Details

No response

SQLModel Version

Traceback (most recent call last): File "", line 1, in ModuleNotFoundError: No module named 'sqlmodel'

Python Version

python3 --version Python 3.9.6

Additional Context

No response

Wrong statement in documentation about SQLModel.metadata.create_all()

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

No code involved

Description

Moving create_all to function here just prevents creation on first import. Python modules are executed only once, you can check it yourself.

So statement "If SQLModel.metadata.create_all(engine) was not in a function and we tried to import something from this module (from this file) in another, it would try to create the database and table every time." is wrong ("every time" in particular).

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.5

Additional Context

No response

How do you define polymorphic models similar to the sqlalchemy ones?

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

from sqlmodel import Relationship, SQLModel, Field, create_engine
from typing import Optional
import uuid


class Principal(SQLModel, table=True):
    __tablename__ = "users"
    id: Optional[uuid.UUID] = Field(primary_key=True,nullable=False,default_factory=uuid.uuid4)
    is_active:bool = Field(default=True)
    type: str = Field(default="principal")
    __mapper_args__ = {
        'polymorphic_on':'type',
        'polymorphic_identity':'principal'
    }

class User(Principal,table=True):
    email: str
    __mapper_args__ = {
        'polymorphic_identity':'user'
    }

class ServiceUser(Principal,table=True):
    name: str
    owner_id: Optional[uuid.UUID] = Field(default=None, foreign_key=('users.id'))
    owner: "User" = Relationship()
    __mapper_args__ = {
        'polymorphic_identity':'serviceuser'
    }

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

engine = create_engine(sqlite_url, echo=True)

SQLModel.metadata.create_all(engine)

Description

  • Run the code above
  • Look at the echo from the database:
<excluded for brevity>
2021-08-26 21:21:45,820 INFO sqlalchemy.engine.Engine
CREATE TABLE users (
        id CHAR(32) NOT NULL,
        is_active BOOLEAN,
        type VARCHAR,
        PRIMARY KEY (id)
)
<excluded for brevity>
  • Sit back and wonder why the inherited objects fields are not included (notice the create table statement not including the fields)

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.10

Additional Context

I think I can fall back to sqlalchemy in this case without any problems, but maybe I am at a loss and it should be done in another way. Removing the "table=True" from the inherited classes makes no difference. Maybe this is also an edge case that should not be supported, but anyway it would be nice to see how this should be handled by people smarter than me. I am currently evaluating rewriting a backend to sqlmodel as it is already implemented in FastApi (which is amazing), and although I know it's early days for this project, I like what it tries to achieve :)

How we can set unique constraint in sql model?

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

pass

Description

How we can set unique constraint in sql model?

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.10

Additional Context

No response

Docs are missing info on how to enable inline errors(configure pyright) (at least in VSCode they are not automatic)

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

"""Main module"""
from typing import Optional

from sqlmodel import Field, SQLModel


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


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='Tom')

a = hero_1.name + 5

Description

https://github.com/tiangolo/sqlmodel/blob/main/docs/index.md#editor-support suggests that inline errors will be automatic. At least in VSCode, they are not. Docs need clarification on how to achieve this.

Wanted Solution

Docs should note that additional vscode config is needed to get inline errors.

Wanted Code

"python.analysis.diagnosticSeverityOverrides": {
        "reportGeneralTypeIssues": "information"
    }


### Alternatives

_No response_

### Operating System

macOS

### Operating System Details

_No response_

### SQLModel Version

0.0.4

### Python Version

3.9.0

### Additional Context

This is the default result you get using sqlmodel in vscode:
![Screenshot 2021-08-31 at 14 43 26](https://user-images.githubusercontent.com/68685/131496606-c6a5f232-af59-440c-920b-ab29b8057832.png) . And it's different from what the docs state.

How to order_by descending?

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

statement = select(Record).order_by(Record.record_id)
records = session.exec(statement).all()
records.reverse()

Description

I'm trying to find a way to perform a select order_by in descending order. I've been performing descending orders in SQLAlchemy with the following line.
select_operation = record_table.select().order_by(record_table.columns.record_id.desc())

I can't see anywhere in the documentation or within intellisense for reversing the sort order. As this project is less than a day old, am I jumping the shark here and it isn't implemented yet, or am I missing something?

Operating System

Linux

Operating System Details

Fedora 34

SQLModel Version

0.0.3

Python Version

3.9.6

Additional Context

No response

Setting PostgreSQL schema

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

from datetime import datetime
from typing import Optional, List
from sqlmodel import Field, SQLModel


class Campaign(SQLModel, table=True):
    campaign_id: Optional[int] = Field(
        default=None,
        primary_key=True,
        schema_extra={'schema': 'test'},
    )
    created_at: Optional[datetime] = Field(
        default=None,
        schema_extra={'schema': 'test'}
    )
    updated_at: Optional[datetime] = Field(
        default=None,
        schema_extra={'schema': 'test'}
    )
    name: str = Field(
        schema_extra={'schema': 'test'}
    )
    description: Optional[str]= Field(
        default=None,
        schema_extra={'schema': 'test'}
    )
    template_id: int = Field(
        schema_extra={'schema': 'test'}
    )
    orders_needed: int = Field(
        schema_extra={'schema': 'test'}
    )
    postcode_areas: List[str] = Field(
        schema_extra={'schema': 'test'}
    )

Description

I've created a model to import and I'm trying to connect to PostgreSQL to an already created database.
But I have my tables in a different schema called test and not public.
After looking through the code I was hoping the input schema_extra would do the trick

schema_extra: Optional[Dict[str, Any]] = None,

But, I must be wrong.

This is the SQL being outputted:

SELECT campaign.campaign_id, campaign.created_at, campaign.updated_at, campaign.name, campaign.description, campaign.template_id, campaign.orders_needed, campaign.postcode_areas 
FROM campaign

Ideally I want it to say:

SELECT campaign.campaign_id, campaign.created_at, campaign.updated_at, campaign.title, campaign.description, campaign.template_id, campaign.orders_needed, campaign.postcode_areas 
FROM test.campaign AS campaign

Is there a way to map a model to a different schema other than the default public schema?

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

3.8.10

Additional Context

No response

FastAPI and Pydantic - Relationships Not Working

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

from typing import List, Optional

from fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select


class TeamBase(SQLModel):
    name: str
    headquarters: str


class Team(TeamBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

    heroes: List["Hero"] = Relationship(back_populates="team")


class TeamCreate(TeamBase):
    pass


class TeamRead(TeamBase):
    id: int


class TeamUpdate(SQLModel):
    id: Optional[int] = None
    name: Optional[str] = None
    headquarters: Optional[str] = None


class HeroBase(SQLModel):
    name: str
    secret_name: str
    age: Optional[int] = None

    team_id: Optional[int] = Field(default=None, foreign_key="team.id")


class Hero(HeroBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

    team: Optional[Team] = Relationship(back_populates="heroes")


class HeroRead(HeroBase):
    id: int


class HeroCreate(HeroBase):
    pass


class HeroUpdate(SQLModel):
    name: Optional[str] = None
    secret_name: Optional[str] = None
    age: Optional[int] = None
    team_id: Optional[int] = None


class HeroReadWithTeam(HeroRead):
    team: Optional[TeamRead] = None


class TeamReadWithHeroes(TeamRead):
    heroes: List[HeroRead] = []


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

connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, echo=True, connect_args=connect_args)


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


def get_session():
    with Session(engine) as session:
        yield session


app = FastAPI()


@app.on_event("startup")
def on_startup():
    create_db_and_tables()


@app.post("/heroes/", response_model=HeroRead)
def create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):
    db_hero = Hero.from_orm(hero)
    session.add(db_hero)
    session.commit()
    session.refresh(db_hero)
    return db_hero


@app.get("/heroes/", response_model=List[HeroRead])
def read_heroes(
    *,
    session: Session = Depends(get_session),
    offset: int = 0,
    limit: int = Query(default=100, lte=100),
):
    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
    return heroes


@app.get("/heroes/{hero_id}", response_model=HeroReadWithTeam)
def read_hero(*, session: Session = Depends(get_session), hero_id: int):
    hero = session.get(Hero, hero_id)
    if not hero:
        raise HTTPException(status_code=404, detail="Hero not found")
    return hero


@app.patch("/heroes/{hero_id}", response_model=HeroRead)
def update_hero(
    *, session: Session = Depends(get_session), hero_id: int, hero: HeroUpdate
):
    db_hero = session.get(Hero, hero_id)
    if not db_hero:
        raise HTTPException(status_code=404, detail="Hero not found")
    hero_data = hero.dict(exclude_unset=True)
    for key, value in hero_data.items():
        setattr(db_hero, key, value)
    session.add(db_hero)
    session.commit()
    session.refresh(db_hero)
    return db_hero


@app.delete("/heroes/{hero_id}")
def delete_hero(*, session: Session = Depends(get_session), hero_id: int):

    hero = session.get(Hero, hero_id)
    if not hero:
        raise HTTPException(status_code=404, detail="Hero not found")
    session.delete(hero)
    session.commit()
    return {"ok": True}


@app.post("/teams/", response_model=TeamRead)
def create_team(*, session: Session = Depends(get_session), team: TeamCreate):
    db_team = Team.from_orm(team)
    session.add(db_team)
    session.commit()
    session.refresh(db_team)
    return db_team


@app.get("/teams/", response_model=List[TeamRead])
def read_teams(
    *,
    session: Session = Depends(get_session),
    offset: int = 0,
    limit: int = Query(default=100, lte=100),
):
    teams = session.exec(select(Team).offset(offset).limit(limit)).all()
    return teams


@app.get("/teams/{team_id}", response_model=TeamReadWithHeroes)
def read_team(*, team_id: int, session: Session = Depends(get_session)):
    team = session.get(Team, team_id)
    if not team:
        raise HTTPException(status_code=404, detail="Team not found")
    return team


@app.patch("/teams/{team_id}", response_model=TeamRead)
def update_team(
    *,
    session: Session = Depends(get_session),
    team_id: int,
    team: TeamUpdate,
):
    db_team = session.get(Team, team_id)
    if not db_team:
        raise HTTPException(status_code=404, detail="Team not found")
    team_data = team.dict(exclude_unset=True)
    for key, value in team_data.items():
        setattr(db_team, key, value)
    session.add(db_team)
    session.commit()
    session.refresh(db_team)
    return db_team


@app.delete("/teams/{team_id}")
def delete_team(*, session: Session = Depends(get_session), team_id: int):
    team = session.get(Team, team_id)
    if not team:
        raise HTTPException(status_code=404, detail="Team not found")
    session.delete(team)
    session.commit()
    return {"ok": True}

Description

Is realationships working for anyone?
I either get null or an empty list.

OK, so, I've copied the last full file preview at the - https://sqlmodel.tiangolo.com/tutorial/fastapi/relationships/
Run it and it creates the Db and the foreign key
Then I've insert the data into the Db.

Checking the docs UI everything looks great
Screenshot 2021-08-26 at 23 33 55

But when I do a request for a hero, team is null
Screenshot 2021-08-26 at 23 36 39

Really not sure what going on, especially when all I have just is copied the code example with no changes?

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.2

Additional Context

No response

CREATE TABLE fails by default in MS SQL Server due to Index = True being the default

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

from typing import Optional

from sqlmodel import Field, SQLModel, create_engine

# DATABASE CONFIG
DB_DRIVER = "ODBC Driver 17 for SQL Server"
DB_HOST = "some_sql_server"
DB_DATABASE = "a_database"

engine = create_engine(
    f"mssql+pyodbc://@{DB_HOST}/{DB_DATABASE}?&driver={DB_DRIVER}"
)


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


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


SQLModel.metadata.create_all(engine)

Description

  • Create a Hero model
  • Attempt to create_all(engine), where the engine is configured against SQL Server.
(pyodbc.ProgrammingError) ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'secret_name' in table 'hero' is of a type that is invalid for use as a key column in an index. (1919) (SQLExecDirectW)")
[SQL: CREATE INDEX ix_hero_secret_name ON hero (secret_name)]
(Background on this error at: https://sqlalche.me/e/14/f405)

I believe this is due to the column being VARCHAR(MAX) which MS SQL Server does not see as a column that can be used for indexing.

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

Python 3.9.6

Additional Context

Happy to write up a PR, but I think the default for indexing either needs to be switched to False by default, or implement some form of dialect check.

P.S. I don't contribue much on GitHub, so please let me know if there's any further context/assistance I can provde. ๐Ÿ˜„

How to make a "timestamp with time zone"?

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 datetime

from typing import List, Optional

import sqlmodel


class AuthUser(sqlmodel.SQLModel, table=True):
  __tablename__ = 'auth_user'
  id: Optional[int] = sqlmodel.Field(default=None, primary_key=True)
  password: str = sqlmodel.Field(max_length=128)
  last_login: datetime.datetime

Description

I'm trying to make the last_login field become a "timestamp with time zone" field in Postgres.

With the above code, it is a "timestamp without time zone".

Operating System

Linux, macOS

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

Python 3.8.1

Additional Context

No response

TypeError: issubclass() arg 1 must be a class when having a field with a complex type

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

from datetime import datetime
from typing import Optional, List, Tuple, Dict, Union
from sqlmodel import Field, SQLModel, create_engine

class SemanticSearch(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    id_user: int
    date_time: datetime
    query: str
    clean_query: str
    semantic_search_result: List[Tuple[int, Dict[str, Union[str, int, float]]]]

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

engine = create_engine(sqlite_url, echo=True)

SQLModel.metadata.create_all(engine)

Description

I would like to create a semantic_search table in the database.db sqlite database with the 6 fields specified.

The last field semantic_search_result with List[Tuple[int, Dict[str, Union[str, int, float]]]] type seems to cause the error.

semantic_search_result looks like this for example:

[
   (0, { "acquisCode": str, "code": str, "level": int, "title": str, "similarity_score": float}),
   (1, { "acquisCode": str, "code": str, "level": int, "title": str, "similarity_score": float}),
   (2, { "acquisCode": str, "code": str, "level": int, "title": str, "similarity_score": float})
]

When running the code I got the following error:

Traceback (most recent call last):
  File "/home/matthieu/Code/Python/fastapi-graphql/test_SQLModel.py", line 6, in <module>
    class SemanticSearch(SQLModel, table=True):
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlmodel/main.py", line 292, in __new__
    col = get_column_from_field(v)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlmodel/main.py", line 415, in get_column_from_field
    sa_type = get_sqlachemy_type(field)
  File "/home/matthieu/anaconda3/envs/sts-transformers-gpu-fresh/lib/python3.8/site-packages/sqlmodel/main.py", line 373, in get_sqlachemy_type
    if issubclass(field.type_, str):
TypeError: issubclass() arg 1 must be a class

I got the same error if I tried to define a subclass of the typing_extensions.TypedDict class:

class SemanticSearchDict(TypedDict):
    acquis_code: str
    code: str
    level: int
    title: str
    similarity_score: float

class SemanticSearch(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    id_user: int
    date_time: datetime
    query: str
    clean_query: str
    semantic_search_result: List[Tuple[int, SemanticSearchDict]]

I couldn't find a solution but #57 seems to have the same problem since having the same error.

Operating System

Linux

Operating System Details

Ubuntu 18.04 LTS

SQLModel Version

0.0.4

Python Version

3.8.8

Additional Context

No response

Flexibly Create Nested Database Entries from Incoming Pydantic/SQLModels

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

# Sudo Code Based on Examples in Docs

class Team(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    headquarters: str


    heroes: List["Hero"] = Relationship(back_populates="team")



class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

    team_id: Optional[int] = Field(default=None, foreign_key="team.id")

    team: Optional[Team] = Relationship(back_populates="heroes")


payload = {
    "name": "Team Name",
    "headquarters": "Whereever".
    "heroes": [
        "name": "Name 1"
        // Other Requied Fields... ๐Ÿ‘‡
    ]
}

with Session(engine) as session:
    Team.create_all_nested(session, payload) # or something?

Description

I would like to do what is described in FastAPI issue #2194

How to make nested sqlalchemy models from nested pydantic models (or python dicts) in a generic way and write them to the database in "one shot".

In the example above, I'd like to pass in the payload to a method and the following to occur.

  • Create new Team entry
  • Create Hero entry and/or Relate the existing Hero to the Team

Similarly, I'd like the same to happen on update. Effectively making writing to the SQL database akin to writing to MongoDB

I don't believe this is supported or haven't gotten it to work, but my main questions are.

  1. Is this supported?
  2. If no, is this a use-case you've thought of?
  3. Are you interested in a PR to support this either as a utility method or some sort of decorator?

Loving working with this so far, thanks for all your hard work!

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.3

Python Version

3.9.6

Additional Context

I have accomplished this with SQLAlchemy in the past by using an auto_init decarator.

from functools import wraps
from typing import Union

from sqlalchemy.orm import MANYTOMANY, MANYTOONE, ONETOMANY


def handle_one_to_many_list(relation_cls, all_elements: list[dict]):
    elems_to_create = []
    updated_elems = []

    for elem in all_elements:
        elem_id = elem.get("id", None)

        existing_elem = relation_cls.get_ref(match_value=elem_id)

        if existing_elem is None:

            elems_to_create.append(elem)

        else:
            for key, value in elem.items():
                setattr(existing_elem, key, value)

            updated_elems.append(existing_elem)

    new_elems = []
    for elem in elems_to_create:
        new_elems = [relation_cls(**elem) for elem in all_elements]

    return new_elems


def auto_init(exclude: Union[set, list] = None):  # sourcery no-metrics
    """Wraps the `__init__` method of a class to automatically set the common
    attributes.

    Args:
        exclude (Union[set, list], optional): [description]. Defaults to None.
    """

    exclude = exclude or set()
    exclude.add("id")

    def decorator(init):
        @wraps(init)
        def wrapper(self, *args, **kwargs):  # sourcery no-metrics
            """
            Custom initializer that allows nested children initialization.
            Only keys that are present as instance's class attributes are allowed.
            These could be, for example, any mapped columns or relationships.

            Code inspired from GitHub.
            Ref: https://github.com/tiangolo/fastapi/issues/2194
            """
            cls = self.__class__
            model_columns = self.__mapper__.columns
            relationships = self.__mapper__.relationships

            session = kwargs.get("session", None)

            for key, val in kwargs.items():
                if key in exclude:
                    continue

                if not hasattr(cls, key):
                    continue
                    # raise TypeError(f"Invalid keyword argument: {key}")

                if key in model_columns:
                    setattr(self, key, val)
                    continue

                if key in relationships:
                    relation_dir = relationships[key].direction.name
                    relation_cls = relationships[key].mapper.entity
                    use_list = relationships[key].uselist

                    if relation_dir == ONETOMANY.name and use_list:
                        instances = handle_one_to_many_list(relation_cls, val)
                        setattr(self, key, instances)

                    if relation_dir == ONETOMANY.name and not use_list:
                        instance = relation_cls(**val)
                        setattr(self, key, instance)

                    elif relation_dir == MANYTOONE.name and not use_list:
                        if isinstance(val, dict):
                            val = val.get("id")

                            if val is None:
                                raise ValueError(f"Expected 'id' to be provided for {key}")

                        if isinstance(val, (str, int)):
                            instance = relation_cls.get_ref(match_value=val, session=session)
                            setattr(self, key, instance)

                    elif relation_dir == MANYTOMANY.name:

                        if not isinstance(val, list):
                            raise ValueError(f"Expected many to many input to be of type list for {key}")

                        if len(val) > 0 and isinstance(val[0], dict):
                            val = [elem.get("id") for elem in val]

                        instances = [relation_cls.get_ref(elem, session=session) for elem in val]
                        setattr(self, key, instances)

            return init(self, *args, **kwargs)

        return wrapper

    return decorator

Usage

class AdminModel(SqlAlchemyBase, BaseMixins):
    name = Column(String, index=True)
    email = Column(String, unique=True, index=True)
    password = Column(String)
    is_superuser = Column(Boolean(), default=False)

    @auto_init(exclude={'is_superuser'})
    def __init__(self, **_):
        this.is_superuser = false

    @classmethod
    def get_ref(cls, match_value: str, match_attr: str = "id"):
        with SessionLocal() as session:
            eff_ref = getattr(cls, match_attr)
            return session.query(cls).filter(eff_ref == match_value).one_or_none()

```decorator

Database loss of connection after extended period of inactivity.

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

from typing import List, Optional

from fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, select

class TeamBase(SQLModel):
    name: str
    headquarters: str

class Team(TeamBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

class TeamCreate(TeamBase):
    pass

class TeamRead(TeamBase):
    id: int

db_url = "mysql://user:pass@localhost/db"

engine = create_engine(db_url)

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

def get_session():
    with Session(engine) as session:
        yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
    create_db_and_tables()

@app.post("/teams/", response_model=TeamRead)
def create_team(*, session: Session = Depends(get_session), team: TeamCreate):
    db_team = Team.from_orm(team)
    session.add(db_team)
    session.commit()
    session.refresh(db_team)
    return db_team


@app.get("/teams/", response_model=List[TeamRead])
def read_teams(
    *,
    session: Session = Depends(get_session),
    offset: int = 0,
    limit: int = Query(default=100, lte=100),
):
    teams = session.exec(select(Team).offset(offset).limit(limit)).all()
    return teams

Description

After an period of inactivity (have not yet isolated how long, roughly a few mins however) the following error will come up.

sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (2013, 'Lost connection to MySQL server during query')

It appears to overcome this in SQLAlchemy, during engine creation you add pool_recycle. eg

engine  = create_engine("mysql://user:pass@localhost/db", pool_recycle=1800)

However if you do the same in SQLmodel the following error occurs.

ERROR:    Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 540, in lifespan
    async for item in self.lifespan_context(app):
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 481, in default_lifespan
    await self.startup()
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 518, in startup
    handler()
  File "/home/brentdreyer/Documents/automation/mnf_database_application/./app/main.py", line 24, in on_startup
    create_db_and_tables()
  File "/home/brentdreyer/Documents/automation/mnf_database_application/./app/db/session.py", line 8, in create_db_and_tables
    SQLModel.metadata.create_all(engine, pool_recycle=1800)
TypeError: create_all() got an unexpected keyword argument 'pool_recycle'

Operating System

Linux

Operating System Details

Fedora KDE 34

SQLModel Version

0.0.4

Python Version

Python 3.9.6

Additional Context

No response

JSON and Array types for sqlmodel

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

from typing import Optional

from sqlmodel import Field, SQLModel, JSON, ARRAY


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: JSON
    age: Optional[int] = None

Description

Got following error:
new_cls = super().__new__(cls, name, bases, dict_used, **config_kwargs) File "pydantic/main.py", line 299, in pydantic.main.ModelMetaclass.__new__ File "pydantic/fields.py", line 411, in pydantic.fields.ModelField.infer File "pydantic/fields.py", line 342, in pydantic.fields.ModelField.__init__ File "pydantic/fields.py", line 456, in pydantic.fields.ModelField.prepare File "pydantic/fields.py", line 670, in pydantic.fields.ModelField.populate_validators File "pydantic/validators.py", line 715, in find_validators RuntimeError: no validator found for <class 'sqlalchemy.sql.sqltypes.JSON'>, seearbitrary_types_allowed in Config

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.8.0

Additional Context

No response

[BUG] Variables with annotation of 'typing.Literal' causes a panic

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

from sqlmodel import SQLModel
from typing import Literal


class Cool(SQLModel, table=True):
    name: Literal["fastapi", "sqlmodel"]


# This code outputs the following to stderr

#   File "main.py", line 5, in <module>
#     class Cool(SQLModel, table=True):
#   File "sqlmodel/main.py", line 292, in __new__
#     col = get_column_from_field(v)
#   File "sqlmodel/main.py", line 415, in get_column_from_field
#     sa_type = get_sqlachemy_type(field)
#   File "sqlmodel/main.py", line 373, in get_sqlachemy_type
#     if issubclass(field.type_, str):
# TypeError: issubclass() arg 1 must be a class

Description

  • Create a sub-class of sqlmodel.main.SQLModel with table=True
  • Add a variable and annotate it with typing.Literal[...]
  • Python raises a TypeError exception at sqlmodel/main:get_sqlachemy_type

This happens because typing.Literal[...] is a function and since SQLModel uses issubclass to get the variable's SQLAlchemy type; issubclass just throws a TypeError since it expects a class.

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

Python 3.9.6

Additional Context

Funny enough Pydantic had quite the same issue pydantic/pydantic#1026 so it can be as easy as importing pydantic.typing.is_literal_type and running an if statement at the top of get_sqlachemy_type

I think the real issue is that typing.Literal is an 'Union' type it receive one or more values but since it's often used for one type (e.g. Literal["r", "w", ...]) we can return the type of all the passed values if they are all the same else None. The values can be retrieved with typing.get_args as a tuple.

Ensure SQLModel and SQLAlchemy Alembic migration parody with automated tests.

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

NA

Description

Add tests that implement the same model in SQLModel and SQLAlchemy, then runs an Alembic migration against an array of databases. This is one way to find disparities in the underlying models generated by SQLModel.

Using Alembic to test the generated models deltas is a good real-world test. Moving from existing SQLAlchemy models to SQLModel's and running migrations is going to be a very common use case.

Wanted Solution

Create a set of isolated docker containers that run sets of Alembic migrations and see if there are any deltas.

Example workflow:

  • Spin up Postgres 13
  • Auto-generate an alembic migration based on the SQLAlchemy schema
  • Apply the Alembic migration to the DB
  • Auto-generate another alembic migration based on the SQLModel schema
  • Ensure that Alembic does not think there should be any migrations.

This could be done on a set of different DBs that SQLAlchemy supports.

Wanted Code

NA

Alternatives

Directly comparing the generated SQLAlchemy and SQLModel model's could be a solution, but it lacks the real-world use case and added complexity of using Alembic.

Operating System

Linux

Operating System Details

Docker

SQLModel Version

0.0.4

Python Version

3.9

Additional Context

I would be happy to set up these types of tests as this is my exact real-world use case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.