Search code examples
pythoncircular-dependencyfastapipydantic

FastAPI / Pydantic circular references in separate files


I would love to use a schema that looks something like the following in FastAPI:

from __future__ import annotations
from typing import List
from pydantic import BaseModel


class Project(BaseModel):
    members: List[User]


class User(BaseModel):
    projects: List[Project]


Project.update_forward_refs()

but in order to keep my project structure clean, I would ofc. like to define these in separate files. How could I do this without creating a circular reference?

With the code above the schema generation in FastAPI works fine, I just dont know how to separate it out into separate files. In a later step I would then instead of using attributes use @propertys to define the getters for these objects in subclasses of them. But for the OpenAPI doc generation, I need this combined - I think.


Solution

  • There are three cases when circular dependency may work in Python:

    • Top of module: import package.module
    • Bottom of module: from package.module import attribute
    • Top of function: works both

    In your situation, the second case "bottom of module" will help. Because you need to use update_forward_refs function to resolve pydantic postponed annotations like this:

    # project.py
    from typing import List
    from pydantic import BaseModel
    
    
    class Project(BaseModel):
        members: "List[User]"
    
    
    from user import User
    Project.update_forward_refs()
    
    # user.py
    from typing import List
    from pydantic import BaseModel
    
    
    class User(BaseModel):
        projects: "List[Project]"
    
    
    from project import Project
    User.update_forward_refs()
    

    Nonetheless, I would strongly discourage you from intentionally introducing circular dependencies