Closed nghianv19940 closed 2 years ago
Document
objects are used to define the mapping between Beanie and a collection in the database, so the error about the collection not being initialized (not existing) is correct, since all Document
s should be mapped to the db.
The problem is that you define UserBase
as:
class UserBase(Document):
...
And then all of your other classes inherit from it, so all of the other classes are also Document
s.
If you want to use the other classes just for validation, then they shouldn't inherit Document
, only a single class should be a Document
in this case, so you can do something like:
from beanie import Document
from pydantic import BaseModel
# Now inherits from pydantic `BaseModel`, not document
class UserBase(BaseModel):
username: str | None
parent_id: str | None
role_id: str | None
payment_type: str | None
disabled: bool | None
note: str | None
access_token: str | None
# User inherits `UserBase` and `Document`
class User(UserBase, Document):
username: str
password: str
disabled: bool = False
salt: str
class Settings:
name = "users"
# Rest of the classes inherit `UserBase` so they're
# only pydantic models, not documents
class UserIn(UserBase):
username: str
password: str
disabled: bool = False
class UserOut(UserBase):
note: str | None
access_token: str | None
This should solve the issue you're having.
Also, you're repeating some of the fields where the field is already inherited, for example UserIn
has username
and disabled
which are both in UserBase
, so password
is needed there. And by marking all of the fields in UserBase
as Optional
you end up losing the validation of required fields being present where you'd probably like to have them.
This page from the FastAPI docs shows a user model as an example: https://fastapi.tiangolo.com/tutorial/extra-models/?h=userout#reduce-duplication
Main thing to note from the page I linked above is that:
UserBase
just has the bare common fields used/required by all subclassesUserIn
has password
as that's what's provided by the userUserInDB
has hashed_password
as the password itself isn't stored in the DBUserOut
just does pass
since no information in addition to what is in UserBase
is returned, and all the stuff in UserBase
is safe to returnUsually the Base
class has just the fields you always require and always return in all models. So in your case UserIn
inherits from UserBase
, so somebody logging in (I guess?) could provide any of the fields from base, including parent
, access_token
, and disabled
, letting them change potentially sensitive fields (I'm not sure if that's how you're actually using the models so that might be wrong).
Thanks @RobertRosca,
Document
objects are used to define the mapping between Beanie and a collection in the database, so the error about the collection not being initialized (not existing) is correct, since allDocument
s should be mapped to the db.The problem is that you define
UserBase
as:class UserBase(Document): ...
And then all of your other classes inherit from it, so all of the other classes are also
Document
s.If you want to use the other classes just for validation, then they shouldn't inherit
Document
, only a single class should be aDocument
in this case, so you can do something like:from beanie import Document from pydantic import BaseModel # Now inherits from pydantic `BaseModel`, not document class UserBase(BaseModel): username: str | None parent_id: str | None role_id: str | None payment_type: str | None disabled: bool | None note: str | None access_token: str | None # User inherits `UserBase` and `Document` class User(UserBase, Document): username: str password: str disabled: bool = False salt: str class Settings: name = "users" # Rest of the classes inherit `UserBase` so they're # only pydantic models, not documents class UserIn(UserBase): username: str password: str disabled: bool = False class UserOut(UserBase): note: str | None access_token: str | None
This should solve the issue you're having.
This info should be on the tutorial page https://roman-right.github.io/beanie/tutorial/defining-a-document/
Main thing to note from the page I linked above is that:
UserBase
just has the bare common fields used/required by all subclassesUserIn
haspassword
as that's what's provided by the userUserInDB
hashashed_password
as the password itself isn't stored in the DBUserOut
just doespass
since no information in addition to what is inUserBase
is returned, and all the stuff inUserBase
is safe to returnUsually the
Base
class has just the fields you always require and always return in all models. So in your caseUserIn
inherits fromUserBase
, so somebody logging in (I guess?) could provide any of the fields from base, includingparent
,access_token
, anddisabled
, letting them change potentially sensitive fields (I'm not sure if that's how you're actually using the models so that might be wrong).
When creating a user, I need all the required fields, including password
. Then I return the newly created user info to the creator without the password
. I think it's a good way to put password
in User and UserIn to not have password
in UserOut. (I hope there is a better way for a child class to exclude fields from the parent class). The same thing applies to disabled
.
All field in UserBase should be optional because there are multiple API route that need the user data. Each should have its own UserIn model (inherited from UserBase), with different requirements in fields. When a user creates his/her account, username
and password
are required. I rewrote the username
to make it required in UserIn.
Hi I'm using beanie with fastapi. this is my model:
my routes:
my beane init function:
if i'm not put UserIn to the init beanie function, then call /users, i will get this error:
Then i put UserIn in the beanie init function. Everything is working.
I just want the UserIn model to validate input data and beanie try to find it in the db. Models not mapped to db should not have anything to do with the db. Right?