BeanieODM / beanie

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

[BUG] Empty BackLink for `Optional[BackLink[ADoc]]` when document has no back-link #920

Closed b-simjoo closed 4 weeks ago

b-simjoo commented 2 months ago

Describe the bug Hi, I'm using FastAPI and Beanie and I have to set of models, one using Beanie for database and other one for API schema. The database has two documents Employee and Department that are linked :

# db.py
class Department(Document):
   id:str
   employees:list[Link["Employee"]]
   ...

class Employee(Document):
   id:str
   department:Optional[BackLink[Department]] = field(original_field="employees", default=None)
   ...

On the other side I have proper Models for both:

# schema.py
class Department(BaseModel):
    id:str
    ...

class Employee(BaseModel):
    id:str
    department:Optional[Department]
    ...

Since I'm using FastAPI, when I return a data instance, it tries to convert from db to schema (using pydantic method Model.model_validate(v,from_attributes=True)).

@router.get("/{emp_id}")
async def get_employee(emp_id: Annotated[str, Path()]) -> schema.Employee:
    return await db.Employee.get(emp_id, fetch_links=True)

Everything works just fine until I try to get an employee that no Department is linked to. Then Employee.department field is an empty BackLink that is not validate or processable for pydantic so it raises a Validation Error:

{'type': 'missing', 'loc': ('response', 'department', 'id'), 'msg': 'Field required', 'input': <beanie.odm.fields.BackLink object at 0x70d990ed0110>, 'url': 'https://errors.pydantic.dev/2.5/v/missing'}

Expected behavior for fields of type Optional[BackLink[ADoc]] set/return None when there is no back-link.

b-simjoo commented 2 months ago

For now I added a pydantic validator on my db model (db.Employee) that fixes the issue

class Employee(Document):
    id:str
    department:Optional[Department]
    @field_validator("department")
    @classmethod
    def validate_backlink(cls, v):
        if isinstance(v, BackLink):
            return None
        return v
github-actions[bot] commented 1 month ago

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

github-actions[bot] commented 4 weeks ago

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