tortoise / tortoise/tortoise-orm

AttributeError: 'int' object has no attribute '_saved_in_db' , Fastapi , Tortoise-orm , pydantic

Open
#1,485 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
5.6k
Forks
516
Avg merge
2d 21h
Merged PRs (30d)
9

Description

I m using fastapi , tortoise-orm and pydantic , everything works fine except the Post method which contain foreign key field.
I get the error saying AttributeError: 'int' object has no attribute '_saved_in_db'
for database I am using elephantSql(postgres)
Repo : https://github.com/lokendra-chaulagain/object-has-no-attribute-in-db-issue

Table model

from tortoise import fields
from tortoise.models import Model

class Table(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=20)

Sale Model

from tortoise import fields
from tortoise.models import Model
from models.Table import Table

class Sale(Model): 
    id = fields.IntField(pk=True)
    discount_amount = fields.FloatField(default=0)
    is_draft = fields.BooleanField(default=True)
    table = fields.ForeignKeyField(
        "models.Table", related_name='sales', on_delete=fields.NO_ACTION)
    table: fields.ForeignKeyRelation[Table] = fields.ForeignKeyField(
        "models.Table", related_name="sales")

Table Schema

from typing import Optional
from pydantic import BaseModel, ValidationError

class TableIn(BaseModel):
    name: str

class TableOut(BaseModel):
    id: int
    name: str

class TableQueryParams(BaseModel):
    page: Optional[int] = 1
    limit: Optional[int] = 5
    name: Optional[str] = None

Sale Schema

from typing import Optional
from pydantic import BaseModel
from models.Table import Table

class SaleIn(BaseModel):
    discount_amount: float
    is_draft: bool
    table: int

class SaleOut(BaseModel):
    id: int
    discount_amount: float
    is_draft: bool
    table: int

class SaleQueryParams(BaseModel):
    page: Optional[int] = 1
    limit: Optional[int] = 5
    table: Optional[int] = None

Sale Route (Controller)

from fastapi import APIRouter, Depends
from typing import List
from models.Sale import Sale
from schemas.saleSchema import SaleIn, SaleOut, SaleQueryParams
saleRouter = APIRouter()

@saleRouter.post("", response_model=SaleOut)
async def create(sale: SaleIn) -> SaleOut:
    # new_sale = await Sale.create(**sale.model_dump())
    # return new_sale

    new_sale = await Sale.create(discount_amount=sale.discount_amount, is_draft=sale.is_draft, table=sale.table)
    saved_sale=new_sale.save()
    return saved_sale

@saleRouter.get("", response_model=List[SaleOut])
async def get_all(query_params: SaleQueryParams = Depends()) -> List[SaleOut]:
    offset = (query_params.page - 1) * query_params.limit
    query = Sale.all()

    if query_params.table:
        query = query.filter(table__icontains=query_params.name)

    sales = await query.offset(offset).limit(query_params.limit)
    return list(sales)
Error:
INFO:     127.0.0.1:58776 - "POST /sales HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 426, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\applications.py", line 292, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
    raise exc
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\middleware\exceptions.py", line 79, in __call__
    raise exc
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\middleware\exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 20, in __call__
    raise e
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\starlette\routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\loken\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\routing.py", line 273, in app
    raw_response = await run_endpoint_function(

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The relevant entry point is the Sale POST route, with the Sale model and SaleIn/SaleOut schemas shown in the issue. Reproduce POST /sales with a foreign-key table value and inspect the complete traceback, then compare the create/save flow with the expected response. Done means the request completes without AttributeError and returns the documented SaleOut shape.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, postgresql, python
Domain
api, backend, database
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.