question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Decoupling data schema from sql schema (pydantic integration)

See original GitHub issue

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 sql model import field, SQLModel
from pydantic import BaseModel

"""
I want to define these separately, and have one of them be extended by the other
"""
UserDataSchema(BaseModel): # Name for comparison
""" Data model, not tied to the database (i.e. sql) itself can be re-used"""
   user_id: int
   project_id: id

# How can this inherit UserDataSchema without re-definition?
UserModel(SQLModel, table=True): # Name for comparison
""" Data model, not tied to the database (i.e. sql) itself can be re-used"""
   user_id: Optional[int] = Field(default=None, foreign_key="user.id")
   project_id:  Optional[int] = Field(default=None, foreign_key="project.id")

Description

The issue at hand is that I am not seeing a way from the docs to decouple the data schema from the database schema. Say I have a large platform, with multiple libraries and services. In such case, if we have a static data schema (like our use case), its very valuable to define the data schema in place (say schema.py as below:

UserDataSchema(BaseModel): # Name for comparison
""" Data model, not tied to the database (i.e. sql) itself can be re-used"""
   user_id: int
   project_id: id

The problem, is that I am not seeing a way to seamlessly translate from the pydantic.BaseModel to the standard SQLModel without having to re-define the entire schema and basically not re-using anything (other than perhaps some functions from the parent class)

I think SQL Alchemy has done it gracefully with their integration of attrs and dataclassess here. Which would look ““in theory””, like this

from sqlalchemy import Table, Column, Integer, ForeignKey
User(SQLModel, UserDataSchema, table=True): # Name for comparison
   __table__  = Table(
         Column("user_id", Integer, ForeignKey("user.id"), primary_key=True),
         Column("project_id", Integer, ForeignKey("project.id"), primary_key=True),
)

Am I missing something? is there a straight forward to accomplish something along these lines? Based on the current docs, the only way to do it would be with:

class UserDataSchema(BaseModel):
    user_id: int
    project_id: int


class User(SQLModel, UserDataSchema, table=True):
    user_id: Optional[int] = Field(default=None, primary_key=True)
    project_id: Optional[int] = Field(default=None, primary_key=True)

However, that defeats the purpose as we have to redefine each attribute again.

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.8

Python Version

3.8

Additional Context

No response

Issue Analytics

  • State:open
  • Created 10 months ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
meirdevcommented, Nov 16, 2022

I think the purpose of SQLModel is to couple the data & database layers (SQLAlchemy & Pydantic) and reuse the same code.

The correct way is to do it the opposite of the way you do it, but you probably know that:

class UserDataSchema(SQLModel):
   user_id: Optional[int] = Field(default=None, foreign_key="user.id")
   project_id: Optional[int] = Field(default=None, foreign_key="project.id")


class UserModel(UserDataSchema, table=True):
    pass
0reactions
phi-fridaycommented, Nov 24, 2022

I don’t know how it is defined, but as an example, it can be defined as follows.

from sqlmodel import SQLModel
from sqlalchemy import ForeignKeyConstraint, PrimaryKeyConstraint
from pydantic import BaseModel


class UserDataSchema(BaseModel):
    user_id: int
    project_id: int


class UserModel(SQLModel, UserDataSchema, table=True):
    __table_args__ = (
        ForeignKeyConstraint(["user_id"], ["user.id"]),
        ForeignKeyConstraint(["project_id"], ["project.id"]),
        PrimaryKeyConstraint("user_id", "project_id"),
    )


# print(repr(getattr(UserModel, "__table__")))
"""
Table(
    'usermodel', MetaData(),
    Column(
        'user_id',
        Integer(),
        ForeignKey('user.id'),
        table=<usermodel>,
        primary_key=True,
        nullable=False
    ),
    Column(
        'project_id',
        Integer(),
        ForeignKey('project.id'),
        table=<usermodel>,
        primary_key=True,
        nullable=False
    ),
    schema=None
)
"""
Read more comments on GitHub >

github_iconTop Results From Across the Web

Issue Manager - Actions · tiangolo/sqlmodel - GitHub
Decoupling data schema from sql schema (pydantic integration) Issue Manager #2397: Issue comment #502 (comment) created by phi-friday. 21 hours ago 44s.
Read more >
Repository Pattern - Cosmic Python
We'll introduce the Repository pattern, a simplifying abstraction over data storage, allowing us to decouple our model layer from the data ...
Read more >
Code Generation - pydantic
The datamodel-code-generator project is a library and command-line utility to generate pydantic models from just about any data source, ...
Read more >
Hooking FastAPI Endpoints up to a Postgres Database
FastAPI depends on Pydantic for data validation, so we'll also ... In doing so, we decouple persistence logic from our application logic.
Read more >
How to Make the Most of Pydantic - Towards Data Science
Explore techniques for data contract validation, higher interoperability with JSON Schemas, and simplified data model processing.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found