better-crud


Namebetter-crud JSON
Version 0.0.6 PyPI version JSON
download
home_pagehttps://github.com/bigrivi/better_crud
SummaryA better CRUD library for FastAPI.
upload_time2025-02-16 09:19:42
maintainerNone
docs_urlNone
authorbigrivi
requires_python>=3.9
licenseApache License 2.0
keywords fastapi crud async sqlalchemy pydantic
VCS
bugtrack_url
requirements fastapi sqlalchemy fastapi_pagination pydantic sqlmodel sqlalchemy_utils passlib aiosqlite httpx pytest pytest-asyncio pytest-cov pytest-order
Travis-CI No Travis.
coveralls test coverage
            <div align="center">
  <h1>BetterCRUD</h1>
</div>
<p align="center" markdown=1>
  <i>A better CRUD library for FastAPI.</i></br>
  <sub>FastAPI CRUD routing library based on class view, you can control everything</sub>
</p>
<p align="center" markdown=1>
<a href="https://github.com/bigrivi/better_crud/actions/workflows/pytest.yml" target="_blank">
  <img src="https://github.com/bigrivi/better_crud/actions/workflows/pytest.yml/badge.svg" alt="Tests"/>
</a>
<a href="https://pypi.org/project/better_crud/" target="_blank">
  <img src="https://img.shields.io/pypi/v/better_crud?color=%2334D058&label=pypi%20package" alt="PyPi Version"/>
</a>
<a href="https://pypi.org/project/better_crud/" target="_blank">
  <img src="https://img.shields.io/pypi/pyversions/better_crud.svg?color=%2334D058" alt="Supported Python Versions"/>
</a>
<a href="https://codecov.io/github/bigrivi/better_crud" target="_blank">
 <img src="https://codecov.io/github/bigrivi/better_crud/graph/badge.svg?token=MEMUT1FH4K"/>
 </a>
</p>


## Requirements
- **Python:** Version 3.9 or newer.
- **FastAPI:** BetterCRUD is built to work with FastAPI, so having FastAPI in your project is essential.
- <b>SQLAlchemy:</b> Version 2.0.30 or newer. BetterCRUD uses SQLAlchemy for database operations.
- <b>Pydantic:</b> Version 2.7.3 or newer. BetterCRUD leverages Pydantic models for data validation and serialization.

## Features
- Fully Async, Synchronization is not supported
- Less boilerplate code
- Configuring static type support
- More flexible custom configuration,Less invasive
- Compatible with both class views and functional views
- Rich filter, paging, and sorting support
- Automated relationship support, query, auto-build and update
- Extensible custom backend





## Default Routes

| Route                | Method     | Description |
| -------------------- | ---------- | ----------- |
| /resource            | **GET**    | Get Many    |
| /resource/{id}       | **GET**    | Get One     |
| /resource            | **POST**   | Create One  |
| /resource/bulk       | **POST**   | Create Many |
| /resource            | **PUT**    | Update One  |
| /resource/{ids}/bulk | **PUT**    | Update Many |
| /resource/{ids}      | **DELETE** | Delete Many |


## Installation
```bash
pip install better-crud
```

## Minimal Example

Prerequisites,Prepare our db, Only asynchronous mode is supported,aiomysql or aiosqlite
**db.py**
```python
from sqlalchemy.orm import DeclarativeBase, declared_attr
from typing import AsyncGenerator
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPool
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
DATABASE_URL = "sqlite+aiosqlite:///crud.db"

class MappedBase(DeclarativeBase):
    @declared_attr.directive
    def __tablename__(cls) -> str:
        return cls.__name__.lower()


class Base(MappedBase):
    __abstract__ = True


engine = create_async_engine(
    DATABASE_URL,
    echo=False,
    poolclass=NullPool
)

SessionLocal = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine,
    class_=AsyncSession,
    expire_on_commit=False,
)


async def get_session() -> AsyncGenerator[AsyncSession, None]:
    async with SessionLocal() as session:
        yield session


async def init_db():
    async with engine.begin() as conn:
        await conn.run_sync(MappedBase.metadata.create_all)
```

First Define Your Model And Schema

**model.py**
```python
from sqlalchemy import String, Integer, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column
from .db import Base


class Pet(Base):
    __tablename__ = "pet"
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    name: Mapped[str] = mapped_column(String(100))
    description: Mapped[str] = mapped_column(String(100))

```

**schema.py**
```python
from typing import Optional, List
from pydantic import BaseModel


class PetBase(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None


class PetPublic(PetBase):
    id: int


class PetCreate(PetBase):
    pass


class PetUpdate(PetBase):
    pass

```

Next we need to create a service:

**service.py**
```python
from better_crud.service.sqlalchemy import SqlalchemyCrudService
from .model import Pet


class PetService(SqlalchemyCrudService[Pet]):
    def __init__(self):
        super().__init__(Pet)

```

Next we need to define the controller and decorate it with the crud decorator
Sure the controller is just a normal class,The crud decorator gives it super powers
**controller.py**
```python
from fastapi import APIRouter, Depends
from better_crud import crud
from .schema import PetCreate, PetUpdate, PetPublic
from .service import PetService

pet_router = APIRouter()


@crud(
    pet_router,
    dto={
        "create": PetCreate,
        "update": PetUpdate
    },
    serialize={
        "base": PetPublic,
    }
)
class PetController():
    service: PetService = Depends(PetService)

```

Next we can register router to the fastapi routing system

**main.py**
```python
from better_crud import BetterCrudGlobalConfig
from fastapi import FastAPI
from contextlib import asynccontextmanager
from .db import get_session, init_db

BetterCrudGlobalConfig.init(
    backend_config={
        "sqlalchemy": {
            "db_session": get_session
        }
    }
)


@asynccontextmanager
async def lifespan(_: FastAPI):
    await init_db()
    # Shutdown
    yield

app = FastAPI(lifespan=lifespan)


def register_router():
    from app.controller import pet_router
    app.include_router(pet_router, prefix="/pet")


register_router()


```

Congratulations, your first CRUD route has been created!

![OpenAPI Route Overview](https://raw.githubusercontent.com/bigrivi/better_crud/main/resources/RouteOverview.png)


## Author

👤 **bigrivi**
* GitHub: [bigrivi](https://github.com/bigrivi)

## 🤝 Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
Don't forget to give the project a star! Thanks again!

1. Fork the Project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

## License

[MIT](LICENSE)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/bigrivi/better_crud",
    "name": "better-crud",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "fastapi, crud, async, sqlalchemy, pydantic",
    "author": "bigrivi",
    "author_email": "sunjianghong@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/4a/e5/12807fcd1f19ab4eaa9c9c99efc82d2b2d102d0ed8b90cf091370a4bcae9/better_crud-0.0.6.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n  <h1>BetterCRUD</h1>\n</div>\n<p align=\"center\" markdown=1>\n  <i>A better CRUD library for FastAPI.</i></br>\n  <sub>FastAPI CRUD routing library based on class view, you can control everything</sub>\n</p>\n<p align=\"center\" markdown=1>\n<a href=\"https://github.com/bigrivi/better_crud/actions/workflows/pytest.yml\" target=\"_blank\">\n  <img src=\"https://github.com/bigrivi/better_crud/actions/workflows/pytest.yml/badge.svg\" alt=\"Tests\"/>\n</a>\n<a href=\"https://pypi.org/project/better_crud/\" target=\"_blank\">\n  <img src=\"https://img.shields.io/pypi/v/better_crud?color=%2334D058&label=pypi%20package\" alt=\"PyPi Version\"/>\n</a>\n<a href=\"https://pypi.org/project/better_crud/\" target=\"_blank\">\n  <img src=\"https://img.shields.io/pypi/pyversions/better_crud.svg?color=%2334D058\" alt=\"Supported Python Versions\"/>\n</a>\n<a href=\"https://codecov.io/github/bigrivi/better_crud\" target=\"_blank\">\n <img src=\"https://codecov.io/github/bigrivi/better_crud/graph/badge.svg?token=MEMUT1FH4K\"/>\n </a>\n</p>\n\n\n## Requirements\n- **Python:** Version 3.9 or newer.\n- **FastAPI:** BetterCRUD is built to work with FastAPI, so having FastAPI in your project is essential.\n- <b>SQLAlchemy:</b> Version 2.0.30 or newer. BetterCRUD uses SQLAlchemy for database operations.\n- <b>Pydantic:</b> Version 2.7.3 or newer. BetterCRUD leverages Pydantic models for data validation and serialization.\n\n## Features\n- Fully Async, Synchronization is not supported\n- Less boilerplate code\n- Configuring static type support\n- More flexible custom configuration\uff0cLess invasive\n- Compatible with both class views and functional views\n- Rich filter, paging, and sorting support\n- Automated relationship support, query, auto-build and update\n- Extensible custom backend\n\n\n\n\n\n## Default Routes\n\n| Route                | Method     | Description |\n| -------------------- | ---------- | ----------- |\n| /resource            | **GET**    | Get Many    |\n| /resource/{id}       | **GET**    | Get One     |\n| /resource            | **POST**   | Create One  |\n| /resource/bulk       | **POST**   | Create Many |\n| /resource            | **PUT**    | Update One  |\n| /resource/{ids}/bulk | **PUT**    | Update Many |\n| /resource/{ids}      | **DELETE** | Delete Many |\n\n\n## Installation\n```bash\npip install better-crud\n```\n\n## Minimal Example\n\nPrerequisites,Prepare our db, Only asynchronous mode is supported,aiomysql or aiosqlite\n**db.py**\n```python\nfrom sqlalchemy.orm import DeclarativeBase, declared_attr\nfrom typing import AsyncGenerator\nfrom sqlalchemy.orm import sessionmaker\nfrom sqlalchemy.pool import NullPool\nfrom sqlalchemy.ext.asyncio import AsyncSession, create_async_engine\nDATABASE_URL = \"sqlite+aiosqlite:///crud.db\"\n\nclass MappedBase(DeclarativeBase):\n    @declared_attr.directive\n    def __tablename__(cls) -> str:\n        return cls.__name__.lower()\n\n\nclass Base(MappedBase):\n    __abstract__ = True\n\n\nengine = create_async_engine(\n    DATABASE_URL,\n    echo=False,\n    poolclass=NullPool\n)\n\nSessionLocal = sessionmaker(\n    autocommit=False,\n    autoflush=False,\n    bind=engine,\n    class_=AsyncSession,\n    expire_on_commit=False,\n)\n\n\nasync def get_session() -> AsyncGenerator[AsyncSession, None]:\n    async with SessionLocal() as session:\n        yield session\n\n\nasync def init_db():\n    async with engine.begin() as conn:\n        await conn.run_sync(MappedBase.metadata.create_all)\n```\n\nFirst Define Your Model And Schema\n\n**model.py**\n```python\nfrom sqlalchemy import String, Integer, ForeignKey\nfrom sqlalchemy.orm import Mapped, mapped_column\nfrom .db import Base\n\n\nclass Pet(Base):\n    __tablename__ = \"pet\"\n    id: Mapped[int] = mapped_column(Integer, primary_key=True)\n    name: Mapped[str] = mapped_column(String(100))\n    description: Mapped[str] = mapped_column(String(100))\n\n```\n\n**schema.py**\n```python\nfrom typing import Optional, List\nfrom pydantic import BaseModel\n\n\nclass PetBase(BaseModel):\n    name: Optional[str] = None\n    description: Optional[str] = None\n\n\nclass PetPublic(PetBase):\n    id: int\n\n\nclass PetCreate(PetBase):\n    pass\n\n\nclass PetUpdate(PetBase):\n    pass\n\n```\n\nNext we need to create a service:\n\n**service.py**\n```python\nfrom better_crud.service.sqlalchemy import SqlalchemyCrudService\nfrom .model import Pet\n\n\nclass PetService(SqlalchemyCrudService[Pet]):\n    def __init__(self):\n        super().__init__(Pet)\n\n```\n\nNext we need to define the controller and decorate it with the crud decorator\nSure the controller is just a normal class,The crud decorator gives it super powers\n**controller.py**\n```python\nfrom fastapi import APIRouter, Depends\nfrom better_crud import crud\nfrom .schema import PetCreate, PetUpdate, PetPublic\nfrom .service import PetService\n\npet_router = APIRouter()\n\n\n@crud(\n    pet_router,\n    dto={\n        \"create\": PetCreate,\n        \"update\": PetUpdate\n    },\n    serialize={\n        \"base\": PetPublic,\n    }\n)\nclass PetController():\n    service: PetService = Depends(PetService)\n\n```\n\nNext we can register router to the fastapi routing system\n\n**main.py**\n```python\nfrom better_crud import BetterCrudGlobalConfig\nfrom fastapi import FastAPI\nfrom contextlib import asynccontextmanager\nfrom .db import get_session, init_db\n\nBetterCrudGlobalConfig.init(\n    backend_config={\n        \"sqlalchemy\": {\n            \"db_session\": get_session\n        }\n    }\n)\n\n\n@asynccontextmanager\nasync def lifespan(_: FastAPI):\n    await init_db()\n    # Shutdown\n    yield\n\napp = FastAPI(lifespan=lifespan)\n\n\ndef register_router():\n    from app.controller import pet_router\n    app.include_router(pet_router, prefix=\"/pet\")\n\n\nregister_router()\n\n\n```\n\nCongratulations, your first CRUD route has been created\uff01\n\n![OpenAPI Route Overview](https://raw.githubusercontent.com/bigrivi/better_crud/main/resources/RouteOverview.png)\n\n\n## Author\n\n\ud83d\udc64 **bigrivi**\n* GitHub: [bigrivi](https://github.com/bigrivi)\n\n## \ud83e\udd1d Contributing\n\nContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\nIf you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag \"enhancement\".\nDon't forget to give the project a star! Thanks again!\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the Branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n## License\n\n[MIT](LICENSE)\n",
    "bugtrack_url": null,
    "license": "Apache License 2.0",
    "summary": "A better CRUD library for FastAPI.",
    "version": "0.0.6",
    "project_urls": {
        "Homepage": "https://github.com/bigrivi/better_crud",
        "Source Code": "https://github.com/bigrivi/better_crud"
    },
    "split_keywords": [
        "fastapi",
        " crud",
        " async",
        " sqlalchemy",
        " pydantic"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2c0c6ef9ea8996401e3bf1d6feb8aebcea1e1ceb6746fc406f709b602e21f83a",
                "md5": "0006aa8282f432a82a330994090902f6",
                "sha256": "e2ce2aa08227f0fedc0cd3f30d8305d30e80abda643d904f409f6cd56b4f5aca"
            },
            "downloads": -1,
            "filename": "better_crud-0.0.6-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0006aa8282f432a82a330994090902f6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 24746,
            "upload_time": "2025-02-16T09:19:40",
            "upload_time_iso_8601": "2025-02-16T09:19:40.746310Z",
            "url": "https://files.pythonhosted.org/packages/2c/0c/6ef9ea8996401e3bf1d6feb8aebcea1e1ceb6746fc406f709b602e21f83a/better_crud-0.0.6-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "4ae512807fcd1f19ab4eaa9c9c99efc82d2b2d102d0ed8b90cf091370a4bcae9",
                "md5": "a492e4be802ec5c99493e5eacd23edd7",
                "sha256": "1fdf93dab11826f7613280bb833c499e5707a314bc42308cdaebc25eb3915bb9"
            },
            "downloads": -1,
            "filename": "better_crud-0.0.6.tar.gz",
            "has_sig": false,
            "md5_digest": "a492e4be802ec5c99493e5eacd23edd7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 21869,
            "upload_time": "2025-02-16T09:19:42",
            "upload_time_iso_8601": "2025-02-16T09:19:42.822014Z",
            "url": "https://files.pythonhosted.org/packages/4a/e5/12807fcd1f19ab4eaa9c9c99efc82d2b2d102d0ed8b90cf091370a4bcae9/better_crud-0.0.6.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-16 09:19:42",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "bigrivi",
    "github_project": "better_crud",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "requirements": [
        {
            "name": "fastapi",
            "specs": []
        },
        {
            "name": "sqlalchemy",
            "specs": [
                [
                    "==",
                    "2.0.30"
                ]
            ]
        },
        {
            "name": "fastapi_pagination",
            "specs": [
                [
                    "==",
                    "0.12.24"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    "==",
                    "2.7.3"
                ]
            ]
        },
        {
            "name": "sqlmodel",
            "specs": [
                [
                    "==",
                    "0.0.22"
                ]
            ]
        },
        {
            "name": "sqlalchemy_utils",
            "specs": [
                [
                    "==",
                    "0.41.2"
                ]
            ]
        },
        {
            "name": "passlib",
            "specs": [
                [
                    "==",
                    "1.7.4"
                ]
            ]
        },
        {
            "name": "aiosqlite",
            "specs": [
                [
                    "==",
                    "0.20.0"
                ]
            ]
        },
        {
            "name": "httpx",
            "specs": []
        },
        {
            "name": "pytest",
            "specs": []
        },
        {
            "name": "pytest-asyncio",
            "specs": []
        },
        {
            "name": "pytest-cov",
            "specs": []
        },
        {
            "name": "pytest-order",
            "specs": []
        }
    ],
    "lcname": "better-crud"
}
        
Elapsed time: 0.62472s