tortoise-orm
tortoise-orm copied to clipboard
Version 0.19.1 is not fetching datetime field
Describe the bug I am using version 0.19.1 of tortoise-orm. It is not fetching the datetime fields of models correctly from from postgres database. This problem is not present in version 0.19.0.
To Reproduce Following is the collated code from multiple files in my project. I have tried to put relevant sections of models and mixins here. I am making a FastAPI app.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from tortoise.contrib.fastapi import register_tortoise
from tortoise import Tortoise
from typing import Any
from typing import Optional, List
from datetime import datetime
from tortoise.fields import IntField, CharField, DatetimeField, BooleanField
from tortoise.fields.relational import ForeignKeyField
from tortoise.fields.base import RESTRICT
from tortoise.models import Model
from typing import List
from fastapi import APIRouter, Query, HTTPException
from tortoise.contrib.fastapi import HTTPNotFoundError
from tortoise.exceptions import DoesNotExist
from tortoise.contrib.pydantic import pydantic_model_creator
# These are my application specific. Code not included.
# from ..utils.hashing import Hasher
# from ..core.config import settings
class EntityMixin(Model):
"""
Entity (common entity) class for other entities to inherit from.
"""
id: int = IntField(
pk=True, index=True, null=False,
description="The primary identifier of this entity.")
name: str = CharField(64, index=True, null=False,
description="The name of this entity.")
status: str = CharField(1, default='A', index=True,
description="Status of this entity: A, I, or D.")
def __str__(self):
return self.name
def is_active(self):
"""
Function to check if the Entity object is in active state.
"""
return self.status == "A"
class Meta:
abstract = True
class CreatorMixin():
"""
Mixin class to define creator and creation time related attributes for
Entity type objects.
"""
created_at: Optional[datetime] = DatetimeField(
auto_now_add=True, null=False)
class Meta:
abstract = True
class LastModifierMixin():
"""
Mixin class to define modifier and modification time related attributes for
Entity type objects.
"""
last_modified_at: Optional[datetime] = DatetimeField(
null=True, index=True, auto_now=True)
class Meta:
abstract = True
class Authuser(EntityMixin, CreatorMixin, LastModifierMixin):
"""
Authuser data model.
"""
login_name: Optional[str] = CharField(
80, description="Login identifier string.", unique=True, null=False)
email_address: Optional[str] = CharField(
80, description="E-mail address of the user.", unique=True, null=False)
password: Optional[str] = CharField(
512, description="Password associated with the user.", null=False)
is_superuser: bool = BooleanField(
description="Indicates if the user is super-user.", null=False)
class Meta:
table = "authusers"
table_description = "Stores records of users who can authenticate."
ordering = ["name", "created_at"]
AuthuserIn = pydantic_model_creator(
Authuser, name="AuthuserIn", include=(
"name", "login_name", "email_address", "password", "is_superuser",
"status"))
AuthuserOut = pydantic_model_creator(
Authuser, name="AuthuserOut", exclude=("password", ),
exclude_readonly=False)
err_response = {404: {"model": HTTPNotFoundError}}
router = APIRouter(
prefix='/authusers',
tags=['Users'],
responses={404: {"description": "Authuser not found."}}
)
@router.get("/", response_model=List[AuthuserOut])
async def get_authuser_list(
skip: int = 0, pick: int = 10) -> [AuthuserOut]:
"""
Fetches and returns a sequence of AuthuserOut objects having status A.
"""
return await AuthuserOut.from_queryset(Authuser.all())
@router.get("/{id}", response_model=AuthuserOut, responses=err_response)
async def get_authuser_single(id: int) -> AuthuserOut:
"""
Fetches and returns an AuthuserOut object for a non-deleted Auther object
of supplied id.
"""
try:
return await AuthuserOut.from_queryset_single(Authuser.get(id=id))
except DoesNotExist:
raise HTTPException(
status_code=404, detail=f"User with id {id} not found")
@router.post("/", response_model=AuthuserOut)
async def create_authuser(
# user: str = Depends(get_current_active_user),
authuser_in: AuthuserIn) -> AuthuserOut:
"""
Create a new authuser from supplied AuthuserIn object, persist it in DB,
and then return it along with its id.
"""
# authuser_in.password = Hasher.hash_create(authuser_in.password)
attrs = authuser_in.dict()
user = await m.Authuser.create(**attrs)
userout = AuthuserOut.from_orm(user)
print(userout.dict()) # Here created_at and last_modified_at fields are found to be null. *BUG*
return userout
# Some values are being picked-up from an environment file .env which gets loaded by the settings module.
# I am not including its code here.
orm_config = {'connections': {'default': settings.DATABASE_URL},
'apps': {
'models': {
'models': ["backend.db.models"],
'default_connection': 'default', }},
'use_tz': True,
'timezone': 'UTC',
'generate_schemas': False,
'add_exception_handlers': True, }
app = FastAPI(
title=settings.PROJECT_TITLE,
description=settings.APP_DESCRIPTION,
version=settings.PROJECT_VERSION,
root_path='/8000',
docs_url='/docs',
redoc_url='/redoc',
openapi_url='/openapi.json')
app.add_middleware(CORSMiddleware, allow_origins=[settings.APP_HOST_URL, ],
allow_credentials=True, allow_methods=["*"],
allow_headers=["*"])
register_tortoise(app, orm_config, generate_schemas=True)
@app.get("/version")
async def get_version() -> Any:
"""
Returns the version number of the application.
"""
return {"version": settings.PROJECT_VERSION}
Expected behavior After a POST request is made in /authusers, the object returned (AuthuserOut) has its created_at and last_modified_at attributes set to null if I use version 0.19.1 of tortoise-orm. Correct date-time is shown if I use version 0.19.0.
Additional context I am using Tortoise ORM for building a FastAPI application. There are multiple files in the project. I have tried to collect only relevant sections of the code to showcase the issue. May be some parts or modules missing from the supplied code.
Show me the code
Show me the code
Sorry for the mess-up. The full text of the issue I had written got lost when github directed me towards the code submission guideline which opened in the same window. While posting it, I didn't notice that it was lost. Now I have rewritten the same by modifying this bug report.
My test result: 0.19.1 can reproduce the bug And 0.19.3 fixed
Thanks. I'll check again.