BeanieODM / beanie

Asynchronous Python ODM for MongoDB
http://beanie-odm.dev/
Apache License 2.0
1.94k stars 203 forks source link

got ValidationError when project an 'id' field #202

Closed lsaint closed 1 year ago

lsaint commented 2 years ago
class UserView(BaseModel):
    id: str
    username: str

class UserModel(Document):
    username: str
    email: str

u = await UserModel.find_one(UserModel.id == "xxx").project(UserView)
print(u.id)

got the error:

pydantic.error_wrappers.ValidationError: 1 validation error for UserView
id
  field required (type=value_error.missing)

if i set id: Optional[PydanticObjectId] = None

got id = None in result

ZettZet commented 2 years ago

Today I had the same problem. And I found why this happens and how to solve it.

The document ID in Mongo is called _id. The first thought is to name the field "_id: PydanticObjectId" in the projection model. But one underscore in Python marks the field as for internal use. Most likely, pydantic does not use such fields for initialization (for the test, I checked on dataclass and it worked; correct if I'm wrong).

Second thought: aliases. And this is the solution. In your case, you can write the following:

from beanie import Document, PydanticObjectId
from pydantic import BaseModel, Field

class UserView(BaseModel):
    id: PydanticObjectId = Field(alias='_id')
    username: str

class UserModel(Document):
    username: str
    email: str

And everything will work!

Perhaps it will later be marked as a bug and fixed, or a better "dirty hack" will be offered.

lsaint commented 2 years ago

Today I had the same problem. And I found why this happens and how to solve it.

The document ID in Mongo is called _id. The first thought is to name the field "_id: PydanticObjectId" in the projection model. But one underscore in Python marks the field as for internal use. Most likely, pydantic does not use such fields for initialization (for the test, I checked on dataclass and it worked; correct if I'm wrong).

Second thought: aliases. And this is the solution. In your case, you can write the following:

from beanie import Document, PydanticObjectId
from pydantic import BaseModel, Field

class UserView(BaseModel):
    id: PydanticObjectId = Field(alias='_id')
    username: str

class UserModel(Document):
    username: str
    email: str

And everything will work!

Perhaps it will later be marked as a bug and fixed, or a better "dirty hack" will be offered.

thank you. it's a good idea for now. In the long run, I prefer this solution #163

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity.

github-actions[bot] commented 1 year ago

This issue was closed because it has been stalled for 14 days with no activity.