tortoise-orm icon indicating copy to clipboard operation
tortoise-orm copied to clipboard

Features similar to django drf source field, I don't know how to implement it

Open smomop opened this issue 1 year ago • 4 comments

class House(Model):
	id = fields.IntField(pk=True)
	house_name: str = fields.CharField(max_length=255)
	info: str = fields.CharField(max_length=255)
	user = fields.ForeignKeyField(
        "models.User",
        on_delete=fields.SET_NULL,
        related_name="houses",
        null=True,
    )

class User(Model):
	id = fields.IntField(pk=True)
	name: str = fields.CharField(max_length=255)
	houses: fields.ReverseRelation["House"]
When I was in get User, like django's drf, 
how to set the user foreign key field in the House model to a source field field, 
so that it can get the name data directly from the User model?

Raw data:
{
    "name": "test",
    "houses": [
        {
            "house_name": "one",
            "info": "xxxxx"
        },
        {
            "house_name": "two",
            "info": "xxxxx"
        }
    ]
}
Expected data:
{
    "name": "test",
    "houses": [
        {
            "house_name": "one",
            "info": "xxxxx",
            "user": "test"
        },
        {
            "house_name": "two",
            "info": "xxxxx",
            "user": "test"
        }
    ]
}

I am pydantic beginner, I don't know how to use pydantic to define the data I want to get.

smomop avatar Aug 21 '23 08:08 smomop

Usually, house object would be dump to {'id': 1, 'house_name': 'xx', 'info': 'xx', 'user': {'id': 1, 'name': 'test'}}

Examples:: https://github.com/tortoise/tortoise-orm/blob/develop/examples/pydantic/recursive.py https://github.com/tortoise/tortoise-orm/blob/develop/examples/pydantic/tutorial_3.py

from tortoise import Tortoise, fields, run_async
from tortoise.contrib.pydantic import pydantic_model_creator
from tortoise.models import Model


class House(Model):
    id = fields.IntField(pk=True)
    house_name: str = fields.CharField(max_length=255)
    info: str = fields.CharField(max_length=255)
    user = fields.ForeignKeyField(
        "models.User",
        on_delete=fields.SET_NULL,
        related_name="houses",
        null=True,
    )


class User(Model):
    id = fields.IntField(pk=True)
    name: str = fields.CharField(max_length=255)
    houses: fields.ReverseRelation["House"]

    class PydanticMeta:
        allow_cycles = True
        max_recursion = 1


async def run():
    await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})
    await Tortoise.generate_schemas()

    # Create object
    user = await User.create(name="test")
    for i in range(1, 3):
        await House.create(house_name=f"house{i}", info=f"info{i}", user=user)
    # Serialise it
    User_Pydantic = pydantic_model_creator(User)
    userpy = await User_Pydantic.from_tortoise_orm(user)

    # As Python dict with Python objects (e.g. datetime)
    print(userpy.model_dump())
    # As serialised JSON (e.g. datetime is ISO8601 string representation)
    print(userpy.model_dump_json(indent=4))


if __name__ == "__main__":
    run_async(run())

Got:

{
    "id": 1,
    "name": "test",
    "houses": [
        {
            "id": 1,
            "house_name": "house1",
            "info": "info1",
            "user": {
                "id": 1,
                "name": "test"
            }
        },
        {
            "id": 2,
            "house_name": "house2",
            "info": "info2",
            "user": {
                "id": 1,
                "name": "test"
            }
        }
    ]
}

waketzheng avatar Sep 03 '23 03:09 waketzheng

but you can never annotate user's name to house, the only way is to select_related, btw why pydantic config exists in Model? Don't you think it break Single responsibility principle?

YAGregor avatar Oct 14 '23 15:10 YAGregor

https://github.com/tortoise/tortoise-orm/blob/develop/examples/pydantic/recursive.py

Not working.

rubbish822 avatar Jan 09 '24 08:01 rubbish822

https://github.com/tortoise/tortoise-orm/blob/develop/examples/pydantic/recursive.py

Not working.

下面的代码可以查询出关联的blogs数据。

`from fastapi import FastAPI from tortoise.contrib.fastapi import register_tortoise from tortoise import fields, models from tortoise.fields.base import CASCADE from tortoise.query_utils import Prefetch from tortoise.contrib.pydantic import pydantic_model_creator

class User(models.Model): name = fields.CharField(max_length=32, unique=True, description='名称')

class Blog(models.Model): name = fields.CharField(max_length=32, unique=True, description='名称') user = fields.ForeignKeyField( 'models.User', on_delete=CASCADE, null=True, related_name='blogs', description='user', )

app = FastAPI()

UserSchema = pydantic_model_creator(User, name="User") BlogSchema = pydantic_model_creator(Blog, name="Blog")

class UserWithBlogsSchema(UserSchema): blogs: list[BlogSchema]

@app.get("/users/", response_model=list[UserWithBlogsSchema]) async def get_users(): users = await User.all().prefetch_related(Prefetch('blogs')) return users

register_tortoise( app, db_url="sqlite://:memory:", modules={"models": ["main"]}, generate_schemas=True, add_exception_handlers=True, )`

rubbish822 avatar Jan 10 '24 02:01 rubbish822