CRUD Sqlalchemy ORM, Pydantic and query on multiple table (like join table) #1830
-
I have trouble on making DB CRUD with two or multiple table (join table) and this is first time i working with Pydantic and FastAPI.Sorry if my question is bullshit :'( Shifdetail.py
User.py
EXPECTED data return look like
And have ShiftDetail schema look like
So how can write CRUD function to return datamodel ShiftDetail (with data get from joining two table ShiftDetail and User) Because in CRUD template, i saw db_session query from self.model only :'(
And of course, i got error (ShiftDetail model dont have owner_email field like ShiftDetail schema expected
|
Beta Was this translation helpful? Give feedback.
Replies: 17 comments
-
You can't simply add a class User(BaseModel):
class Config:
orm_mode = True
id: str
email: str
hashed_password: str
class ShiftDetailBase(BaseModel)
# add field for the owner (reference User model)
# I believe you can remove the owner_id field
owner: User The response would then look like:
If you want |
Beta Was this translation helpful? Give feedback.
-
@paul121 . Sure, thank for your guide about schema. But i very confuse about making CRUD to return data that i need. I have some code to return list of ShiftDetail (not include Owner)
And i dont know to to make data include Owner data ... |
Beta Was this translation helpful? Give feedback.
-
Can we think about the query in the reverse direction? This should return only the ShiftDetails that belong to one user. (not tested) ... eg: def get_shifts_by_owner_id(
self, db_session: Session, *, owner_id: str, skip=0, limit=100
) -> List[ShiftDetail]:
return (
db_session.query(model.User.shiftdetails). # query on the User model, select only the shift details
.filter(model.User.id == owner_id)
.offset(skip)
.limit(limit)
.all()
) |
Beta Was this translation helpful? Give feedback.
-
Just query on one table only and model User dont have shiftdetails. It doesn't work :'( |
Beta Was this translation helpful? Give feedback.
-
hmm, sorry that didn't work @tatdatpham! |
Beta Was this translation helpful? Give feedback.
-
Thanks for the help here @paul121 ! 👏 🍰 @tatdatpham First make sure that your SQLAlchemy query is returning the data that you want. Run that code outside of your FastAPI app and make sure it works. If you need to understand better how to use SQLAlchemy, check the tutorial: https://docs.sqlalchemy.org/en/13/orm/tutorial.html Then, after you have your data, you have to convert it to have the shape of the model that you want to return. So, probably iterating in each of the rows in the result and putting all that in Then with that you can finally try to put it in a Pydantic model and see where the error is. But first you have to debug the initial part and make sure that you are getting the data that you need, and then that you are converting it to the shape that you need. |
Beta Was this translation helpful? Give feedback.
-
As tiangolo said, verify you are returning the data you want (you should be). Your query should already be returning the data you need via SQLAlchemy here:
then add to your schema like so:
and then be sure to import the User Schema from where you defined that (.user for example).
It will be nested, and not inline like you expected - I didn't like how this returns but just means dealing with it differently when consuming.
import that in your Shiftdetail.py and use it in the schema in place of "User" :
Then it will just return the email, and not all the user fields. |
Beta Was this translation helpful? Give feedback.
This comment was marked as off-topic.
This comment was marked as off-topic.
-
Weird... I've done exactly what you say here for my model, but I'm still getting
Both imported into input_template_base.py schema file where I have:
Have checked my db query and it's returning the correct orm object and I can access those fields...
Any ideas? |
Beta Was this translation helpful? Give feedback.
-
@Cozmo25 I'm not sure I'm following correctly, but I think that by having something like: # Properties to return to client
class InputTemplateDetail(InputTemplateDetailInDBBase):
template_name: InputTemplateShared
class Config:
orm_mode = True And then, before that: class InputTemplateShared(InputTemplateBase):
name: str
class Config:
orm_mode = True It would expect something like: {
"template_name": {
"name": "anode_graphite"
}
} Notice the nested Could that be the problem? |
Beta Was this translation helpful? Give feedback.
-
@tiangolo Thank you for the response much appreciated. It’s very likely the problem, I’m just not sure how to create the structure I need (not nested instead of nested) where I have a join between tables. |
Beta Was this translation helpful? Give feedback.
-
@Cozmo25 I think that instead of: class InputTemplateDetail(InputTemplateDetailInDBBase):
template_name: InputTemplateShared
class Config:
orm_mode = True something like this could work: class InputTemplateDetail(InputTemplateDetailInDBBase):
template_name: str
class Config:
orm_mode = True |
Beta Was this translation helpful? Give feedback.
-
Thanks for this @tiangolo. I tried that approach but it still gives me pydantic errors (field missing). When I get the InputTemplateDetail object back from the DB I need to access template name via: How do I access that property here?
|
Beta Was this translation helpful? Give feedback.
-
hi @Cozmo25, have you succeeded to get the data inline instead of nested? |
Beta Was this translation helpful? Give feedback.
-
Hi @adriendod Did you manage to get it inline? |
Beta Was this translation helpful? Give feedback.
-
@wedwardbeck Your response works but it returns a nested response and not inline.... as in {
"owner": {
"email_address": "[email protected]"
}
} Anyway it can only return "email_address": "[email protected]" Thanks |
Beta Was this translation helpful? Give feedback.
-
@AthreyVinay hi! How did you manage to get it inline
|
Beta Was this translation helpful? Give feedback.
You can't simply add a
user_email
field to that schema and expect it to be populated. Rather,you need to also create a User schema. Otherwise Pydantic won't now how to connect the two models.
The response would then look like: