https://github.com/satorudev976/sqlalchemy-nest
Nested Model With SQLAlchemy
https://github.com/satorudev976/sqlalchemy-nest
database nested orm python sqlalchemy
Last synced: 6 months ago
JSON representation
Nested Model With SQLAlchemy
- Host: GitHub
- URL: https://github.com/satorudev976/sqlalchemy-nest
- Owner: satorudev976
- License: mit
- Created: 2023-12-31T12:10:52.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-02-18T09:18:05.000Z (almost 2 years ago)
- Last Synced: 2025-08-26T11:44:45.213Z (6 months ago)
- Topics: database, nested, orm, python, sqlalchemy
- Language: Python
- Homepage:
- Size: 126 KB
- Stars: 2
- Watchers: 1
- Forks: 1
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# sqlalchemy-nest
[](https://pypi.org/project/sqlalchemy-nest/)
[](https://pypi.org/project/sqlalchemy-nest/)
[](https://pepy.tech/project/sqlalchemy-nest)
[](https://github.com/satorudev976/sqlalchemy-nest/actions/workflows/ci.yml)
[](https://codecov.io/gh/satorudev976/sqlalchemy-nest)
[](https://codeclimate.com/github/satorudev976/sqlalchemy-nest/maintainability)
sqlalchemy-nest is easy create nested models for sqlalchemy
### Why?? 🧐🧐
The default constructor of ```declarative_base()``` in sqlalchemy is as follows
```python
def _declarative_constructor(self: Any, **kwargs: Any) -> None:
cls_ = type(self)
for k in kwargs:
if not hasattr(cls_, k):
raise TypeError(
"%r is an invalid keyword argument for %s" % (k, cls_.__name__)
)
setattr(self, k, kwargs[k])
```
So can’t create nested model by unpacking schema like below. OMG !!!
```python
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class Root(Base):
__tablename__ = "root"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100))
branches = relationship("Branch", back_populates="root", uselist=True, lazy="joined")
class Branch(Base):
__tablename__ = "branch"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100))
root_id = Column(Integer, ForeignKey("root.id"))
root = relationship("Root")
root = {
'name': 'root',
'branches': [
{
'name': 'branch',
},
]
}
created_root = Root(**root)
>>> AttributeError: 'dict' object has no attribute '_sa_instance_state'
```
### Installation
```
pip install sqlalchemy-nest
```
### Create Nested Model
1. Set declarative_base constructor
use ```declarative_nested_model_constructor``` for declarative_base constructor
```python
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy_nest import declarative_nested_model_constructor
Base = declarative_base(constructor=declarative_nested_model_constructor)
class Root(Base):
__tablename__ = "root"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100))
branches = relationship("Branch", back_populates="root", uselist=True, lazy="joined")
class Branch(Base):
__tablename__ = "branch"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100))
root_id = Column(Integer, ForeignKey("root.id"))
root = relationship("Root")
```
1. Initialization from **kwargs
sets attributes on the constructed instance using the names and values in kwargs.
```python
root = {
'name': 'root',
'branches': [
{
'name': 'branch',
},
]
}
>>> session.add(Root(**root))
>>> session.commit()
>>> added_root: Root = session.query(Root).filter(Root.id == 1).first()
Root(id=1, name='root', branches=[
Branch(id=1, name='branch', root_id=1)]
)
```
### Merge Nested Model
1. Set declarative_base constructor and cls
use ```declarative_nested_model_constructor``` and ```BaseModel``` for declarative_base
```python
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy_nest import declarative_nested_model_constructor
from sqlalchemy_nest.orm import BaseModel
Base = declarative_base(cls=BaseModel, constructor=declarative_nested_model_constructor)
class Root(Base):
__tablename__ = "root"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100))
branches = relationship("Branch", back_populates="root", uselist=True, lazy="joined")
class Branch(Base):
__tablename__ = "branch"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100))
root_id = Column(Integer, ForeignKey("root.id"))
root = relationship("Root")
```
1. Update from **kwargs
```python
root = {
'name': 'root',
'branches': [
{
'name': 'branch',
},
]
}
>>> session.add(Root(**root))
>>> session.commit()
>>> added_root: Root = session.query(Root).filter(Root.id == 1).first()
Root(id=1, name='root', branches=[
Branch(id=1, name='branch', root_id=1)]
)
update_root = {
'id': 1,
'name': 'updated_root',
'branches': [
{
'id': 1,
'name': 'updated_branch',
},
{
'name': 'created_branch',
},
]
}
>>> added_root.merge(**update_root)
>>> session.commit()
>>> updated_root: Root = session.query(Root).filter(Root.id == 1).first()
Root(id=1, name='updated_root', branches=[
Branch(id=1, name='updated_branch', root_id=1),
Branch(id=2, name='created_branch', root_id=1)]
)
```
### Development
Please refer to the [CONTRIBUTING](https://github.com/satorudev976/sqlalchemy-nest/blob/main/CONTRIBUTING.md)
### Example
[Sample Code](https://github.com/satorudev976/sqlalchemy-nest/tree/main/examples) using FastAPI and SQLAlchemy