Null value if the field has an alias #8149
Replies: 14 comments
-
@francbartoli I think the problem is that you are specifying an alias I guess the first thing to try is to change the |
Beta Was this translation helpful? Give feedback.
-
@tiangolo I cannot use |
Beta Was this translation helpful? Give feedback.
-
I see, then you can try |
Beta Was this translation helpful? Give feedback.
-
@tiangolo I've tried but now the field is populated with an empty list: Body request: {
"metadata": [
{
"title": "thistle"
}
],
"tid": "thistle"
} Response is 201 with
But effectively the record has |
Beta Was this translation helpful? Give feedback.
-
@francbartoli I'm reading this from mobile and still haven't tested it but I think (as suggested by @tiangolo) you could try and define you model like class BaseType(BaseModel):
metadata : List[metadata] = Schema (None, alias="_metadata")
class Config:
allow_population_by_alias = True This way your model's |
Beta Was this translation helpful? Give feedback.
-
@stefanondisponibile Applying your changes would end up with the following error:
I guess the problem is with the name |
Beta Was this translation helpful? Give feedback.
-
🤔 I'm not sure from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from pydantic import BaseModel
from pprint import pprint
from typing import Any
from fastapi.encoders import jsonable_encoder
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'some_table'
id = Column(Integer, primary_key=True)
metadata_ = Column(String(50))
class Test(BaseModel):
id: int = 42
metadata: Any = ...
class Config:
orm_mode = True
fields = {"metadata": {"alias": "metadata_"}}
engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
c_in = Test(**{"metadata_": "foo"})
c_in = jsonable_encoder(c_in, by_alias=True)
c = SomeClass(**c_in)
session.add(c)
session.commit()
for t in session.query(SomeClass).all():
pprint(vars(t))
print()
print("ORM MODE:")
print(Test.from_orm(t).json())
print(jsonable_encoder(Test.from_orm(t), by_alias=False))
print("\nSTARRED:")
print(Test(**vars(t)).json())
print(jsonable_encoder(Test(**vars(t)), by_alias=False))
|
Beta Was this translation helpful? Give feedback.
-
Hi @stefanondisponibile, sorry perhaps I didn't explain my use case properly. I was meaning this situation which would be required to be consistently conforming with the models' name of my OpenAPI definition. from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from pydantic import BaseModel
from pprint import pprint
from typing import Any, List
from fastapi.encoders import jsonable_encoder
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'some_table'
id = Column(Integer, primary_key=True)
metadata_ = Column(postgresql.JSONB, default=[])
class metadata(BaseModel):
title: str = None
class Test(BaseModel):
id: int = 42
metadata: List[metadata] = ...
class Config:
orm_mode = True
fields = {"metadata": {"alias": "metadata_"}}
engine = create_engine('postgresql://')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
c_in = Test(**{"metadata_": [{"title": "foo"}]})
c_in = jsonable_encoder(c_in, by_alias=True)
c = SomeClass(**c_in)
session.add(c)
session.commit()
for t in session.query(SomeClass).all():
pprint(vars(t))
print()
print("ORM MODE:")
print(Test.from_orm(t).json())
print(jsonable_encoder(Test.from_orm(t), by_alias=False))
print("\nSTARRED:")
print(Test(**vars(t)).json())
print(jsonable_encoder(Test(**vars(t)), by_alias=False)) |
Beta Was this translation helpful? Give feedback.
-
Oh yes, sorry, I hadn't read properly. docker run --name tmp-postgres -p 5432:5432 -e POSTGRES_PASSWORD=foo -e POSTGRES_USER=foo postgres from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from pydantic import BaseModel
from pprint import pprint
from typing import Any, List, Dict
from fastapi.encoders import jsonable_encoder
from fastapi import FastAPI
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'some_table'
id = Column(Integer, primary_key=True)
metadata_ = Column(postgresql.JSONB, default=[])
class Metadata(BaseModel):
title: str = None
class Test(BaseModel):
metadata_: List[Metadata] = ...
class Config:
orm_mode = True
fields = {"metadata_": {"alias": "metadata"}}
allow_population_by_alias = True
engine = create_engine('postgresql://foo:foo@localhost:5432')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
app = FastAPI()
@app.get("/test", response_model=List[Test])
def read_tests():
tests = session.query(SomeClass).all()
return tests
@app.post("/test", response_model=Test)
def create_test(test_in: Test):
test_in = jsonable_encoder(test_in, by_alias=False)
test = SomeClass(**test_in)
session.add(test)
session.commit()
session.refresh(test)
return test curl -X POST -H "Content-Type: application/json" -d '{"metadata": [{"title": "foo"}, {"title": "bar"}]}' http://localhost:8000/test {
"metadata": [
{
"title": "foo"
},
{
"title": "bar"
}
]
} curl -X GET http://localhost:8000/test [
{
"metadata": [
{
"title": "foo"
},
{
"title": "bar"
}
]
}
] Is this the output you would expect @francbartoli ? One thing I noticed, though, is that adding |
Beta Was this translation helpful? Give feedback.
-
Since I noticed some errors in my code (don't know why the heck hadn't put the response model into the decorator, sorry about that), I decided to cut to the chase and set up a little app for it. |
Beta Was this translation helpful? Give feedback.
-
Thanks for all your help here @stefanondisponibile ! @francbartoli It might be the case that the problem is related to #332 if that's the case, you could try with Otherwise, the best would be to write a simple/minimal example program, possibly copying from the SQL tutorial, and replicating your error. That way it would be easier to debug what is happening and what you would expect to happen. |
Beta Was this translation helpful? Give feedback.
-
@tiangolo thanks, it is related to that issue. I'm going to test with Pydantic 0.30 if that solves the issue |
Beta Was this translation helpful? Give feedback.
-
closed by 0.33.0 |
Beta Was this translation helpful? Give feedback.
-
Thanks for reporting back and closing the issue @francbartoli ! 🎉 |
Beta Was this translation helpful? Give feedback.
-
Describe the bug
A model defined by a field with an alias gives a null value in the response.
To Reproduce
Steps to reproduce the behavior:
models/test.py
db_models/test.py
Expected behavior
Before 0.30.0 I've seen it working but the response had
"metadata": null
Environment:
Beta Was this translation helpful? Give feedback.
All reactions