sqlalchemy-nest


Namesqlalchemy-nest JSON
Version 1.2.2 PyPI version JSON
download
home_pagehttps://github.com/satorudev976/sqlalchemy-nest.git
Summaryeasy create nested models for sqlalchemy
upload_time2024-02-18 09:17:00
maintainer
docs_urlNone
authorsatoru
requires_python>=3.9,<4.0
licenseMIT
keywords sqlalchemy nest sqlalchemy-nest
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # sqlalchemy-nest

[![PyPI - Version](https://img.shields.io/pypi/v/sqlalchemy-nest)](https://pypi.org/project/sqlalchemy-nest/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlalchemy-nest)](https://pypi.org/project/sqlalchemy-nest/)
[![Downloads](https://static.pepy.tech/badge/sqlalchemy-nest)](https://pepy.tech/project/sqlalchemy-nest)
[![CI](https://github.com/satorudev976/sqlalchemy-nest/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/satorudev976/sqlalchemy-nest/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/satorudev976/sqlalchemy-nest/graph/badge.svg?token=67ESOOAA5E)](https://codecov.io/gh/satorudev976/sqlalchemy-nest)
[![Maintainability](https://api.codeclimate.com/v1/badges/7c8a77a2447deec781ce/maintainability)](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

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/satorudev976/sqlalchemy-nest.git",
    "name": "sqlalchemy-nest",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9,<4.0",
    "maintainer_email": "",
    "keywords": "sqlalchemy,nest,sqlalchemy-nest",
    "author": "satoru",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/fa/19/a2802204d166a110ae1dfb8178277e22b88a9914fa27288916b2cdd82ecb/sqlalchemy_nest-1.2.2.tar.gz",
    "platform": null,
    "description": "# sqlalchemy-nest\n\n[![PyPI - Version](https://img.shields.io/pypi/v/sqlalchemy-nest)](https://pypi.org/project/sqlalchemy-nest/)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlalchemy-nest)](https://pypi.org/project/sqlalchemy-nest/)\n[![Downloads](https://static.pepy.tech/badge/sqlalchemy-nest)](https://pepy.tech/project/sqlalchemy-nest)\n[![CI](https://github.com/satorudev976/sqlalchemy-nest/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/satorudev976/sqlalchemy-nest/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/satorudev976/sqlalchemy-nest/graph/badge.svg?token=67ESOOAA5E)](https://codecov.io/gh/satorudev976/sqlalchemy-nest)\n[![Maintainability](https://api.codeclimate.com/v1/badges/7c8a77a2447deec781ce/maintainability)](https://codeclimate.com/github/satorudev976/sqlalchemy-nest/maintainability)\n\nsqlalchemy-nest is easy create nested models for sqlalchemy\n\n### Why?? \ud83e\uddd0\ud83e\uddd0\n\nThe default constructor of ```declarative_base()``` in sqlalchemy is as follows\n\n```python\ndef _declarative_constructor(self: Any, **kwargs: Any) -> None:\n    cls_ = type(self)\n    for k in kwargs:\n        if not hasattr(cls_, k):\n            raise TypeError(\n                \"%r is an invalid keyword argument for %s\" % (k, cls_.__name__)\n            )\n        setattr(self, k, kwargs[k])\n\n```\n\nSo can\u2019t create nested model by unpacking schema like below. OMG !!!\n\n```python\nfrom sqlalchemy import Column, ForeignKey, Integer, String\nfrom sqlalchemy.orm import declarative_base, relationship\n\nBase = declarative_base()\n\nclass Root(Base):\n    __tablename__ = \"root\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String(100))\n\n    branches = relationship(\"Branch\", back_populates=\"root\", uselist=True, lazy=\"joined\")\n\nclass Branch(Base):\n    __tablename__ = \"branch\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String(100))\n    root_id = Column(Integer, ForeignKey(\"root.id\"))\n\n    root = relationship(\"Root\")\n\nroot = {\n    'name': 'root',\n    'branches': [\n        {\n            'name': 'branch',\n        },\n    ]\n}\n\ncreated_root = Root(**root)\n>>> AttributeError: 'dict' object has no attribute '_sa_instance_state'\n```\n\n\n### Installation\n\n```\npip install sqlalchemy-nest\n```\n\n### Create Nested Model\n\n1. Set declarative_base constructor\n\n    use ```declarative_nested_model_constructor``` for declarative_base constructor\n\n    ```python\n    from sqlalchemy import Column, ForeignKey, Integer, String\n    from sqlalchemy.orm import declarative_base, relationship\n    from sqlalchemy_nest import declarative_nested_model_constructor\n\n    Base = declarative_base(constructor=declarative_nested_model_constructor)\n\n    class Root(Base):\n        __tablename__ = \"root\"\n\n        id = Column(Integer, primary_key=True, autoincrement=True)\n        name = Column(String(100))\n\n        branches = relationship(\"Branch\", back_populates=\"root\", uselist=True, lazy=\"joined\")\n\n    class Branch(Base):\n        __tablename__ = \"branch\"\n\n        id = Column(Integer, primary_key=True, autoincrement=True)\n        name = Column(String(100))\n        root_id = Column(Integer, ForeignKey(\"root.id\"))\n\n        root = relationship(\"Root\")\n    ```\n\n1. Initialization from **kwargs\n\n    sets attributes on the constructed instance using the names and values in kwargs.\n\n    ```python\n    root = {\n        'name': 'root',\n        'branches': [\n            {\n                'name': 'branch',\n            },\n        ]\n    }\n    >>> session.add(Root(**root))\n    >>> session.commit()\n    >>> added_root: Root = session.query(Root).filter(Root.id == 1).first()\n    Root(id=1, name='root', branches=[\n        Branch(id=1, name='branch', root_id=1)]\n    )\n    ```\n\n### Merge Nested Model\n\n1. Set declarative_base constructor and cls\n\n    use ```declarative_nested_model_constructor```  and ```BaseModel``` for declarative_base\n\n    ```python\n    from sqlalchemy import Column, ForeignKey, Integer, String\n    from sqlalchemy.orm import declarative_base, relationship\n    from sqlalchemy_nest import declarative_nested_model_constructor\n    from sqlalchemy_nest.orm import BaseModel\n\n    Base = declarative_base(cls=BaseModel, constructor=declarative_nested_model_constructor)\n\n    class Root(Base):\n        __tablename__ = \"root\"\n\n        id = Column(Integer, primary_key=True, autoincrement=True)\n        name = Column(String(100))\n\n        branches = relationship(\"Branch\", back_populates=\"root\", uselist=True, lazy=\"joined\")\n\n    class Branch(Base):\n        __tablename__ = \"branch\"\n\n        id = Column(Integer, primary_key=True, autoincrement=True)\n        name = Column(String(100))\n        root_id = Column(Integer, ForeignKey(\"root.id\"))\n\n        root = relationship(\"Root\")\n\n    ```\n\n1. Update from **kwargs\n\n\n    ```python\n    root = {\n        'name': 'root',\n        'branches': [\n            {\n                'name': 'branch',\n            },\n        ]\n    }\n    >>> session.add(Root(**root))\n    >>> session.commit()\n    >>> added_root: Root = session.query(Root).filter(Root.id == 1).first()\n    Root(id=1, name='root', branches=[\n        Branch(id=1, name='branch', root_id=1)]\n    )\n\n    update_root = {\n        'id': 1,\n        'name': 'updated_root',\n        'branches': [\n            {\n                'id': 1,\n                'name': 'updated_branch',\n            },\n            {\n                'name': 'created_branch',\n            },\n        ]\n    }\n    >>> added_root.merge(**update_root)\n    >>> session.commit()\n    >>> updated_root: Root = session.query(Root).filter(Root.id == 1).first()\n    Root(id=1, name='updated_root', branches=[\n        Branch(id=1, name='updated_branch', root_id=1),\n        Branch(id=2, name='created_branch', root_id=1)]\n    )\n    ```\n\n### Development\n\nPlease refer to the [CONTRIBUTING](https://github.com/satorudev976/sqlalchemy-nest/blob/main/CONTRIBUTING.md)\n\n### Example\n\n[Sample Code](https://github.com/satorudev976/sqlalchemy-nest/tree/main/examples) using FastAPI and SQLAlchemy\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "easy create nested models for sqlalchemy",
    "version": "1.2.2",
    "project_urls": {
        "Homepage": "https://github.com/satorudev976/sqlalchemy-nest.git",
        "Repository": "https://github.com/satorudev976/sqlalchemy-nest.git"
    },
    "split_keywords": [
        "sqlalchemy",
        "nest",
        "sqlalchemy-nest"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4deb95235594c5c4c37d0422f4ada9f01a137ca1c37446d0564757847e29bea3",
                "md5": "150325d933991092a7b17c349174cf23",
                "sha256": "5dcab057575605e47c5821b745ee14ab9030e671c3aa1ec6341b9d3f49ac8aa7"
            },
            "downloads": -1,
            "filename": "sqlalchemy_nest-1.2.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "150325d933991092a7b17c349174cf23",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9,<4.0",
            "size": 5214,
            "upload_time": "2024-02-18T09:16:58",
            "upload_time_iso_8601": "2024-02-18T09:16:58.954663Z",
            "url": "https://files.pythonhosted.org/packages/4d/eb/95235594c5c4c37d0422f4ada9f01a137ca1c37446d0564757847e29bea3/sqlalchemy_nest-1.2.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fa19a2802204d166a110ae1dfb8178277e22b88a9914fa27288916b2cdd82ecb",
                "md5": "536ebf509093dfdeebbaf99e2ad81d36",
                "sha256": "764c92a6a43d1856eb28f6e70d43931f7d959cffd6a459582b537ef4cd59e2f7"
            },
            "downloads": -1,
            "filename": "sqlalchemy_nest-1.2.2.tar.gz",
            "has_sig": false,
            "md5_digest": "536ebf509093dfdeebbaf99e2ad81d36",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9,<4.0",
            "size": 4625,
            "upload_time": "2024-02-18T09:17:00",
            "upload_time_iso_8601": "2024-02-18T09:17:00.292705Z",
            "url": "https://files.pythonhosted.org/packages/fa/19/a2802204d166a110ae1dfb8178277e22b88a9914fa27288916b2cdd82ecb/sqlalchemy_nest-1.2.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-18 09:17:00",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "satorudev976",
    "github_project": "sqlalchemy-nest",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "sqlalchemy-nest"
}
        
Elapsed time: 0.19043s