简体   繁体   中英

Definining recursive models in Pydantic?

How can I define a recursive Pydantic model?

Here's an example of what I mean:

from typing import List
from pydantic import BaseModel

class Task(BaseModel):
    name: str
    subtasks: List[Task] = []

but when I run that I get the following error:

NameError                                 Traceback (most recent call last)
<ipython-input-1-c6dca1d390fe> in <module>
      2 from pydantic import BaseModel
      3
----> 4 class Task(BaseModel):
      5     name: str
      6     subtasks: List[Task] = []

<ipython-input-1-c6dca1d390fe> in Task()
      4 class Task(BaseModel):
      5     name: str
----> 6     subtasks: List[Task] = []
      7

NameError: name 'Task' is not defined

I looked through the documentation but couldn't find anything. For example, at the page on "Recursive Models" , but it seems to be about nesting subtypes of BaseModel not about a recursive type definition.

Thanks for your help!

Either put from __future__ import annotations at the top of the file, or change your annotation to List['Task'] .

The relevant pydantic documentation is here: https://pydantic-docs.helpmanual.io/usage/postponed_annotations/

But the error in your question is not pydantic specific, that's just how type annotations work.

I found myself in a situation in which I want to run a root validator on the class. What happens is that, although the above solution seem to work find in some cases, the value of the recursive field subtasks doesn't show up in the values dictionary parameter of the @root_validator .

I ended up with declaring

subtasks: List[Dict]

and recursively build the subtasks objects in the @root_validator :

subtasks = values.get('subtasks')
if subtasks:
    values['subtasks']=[Task(**subtask) for subtask in subtasks]

Expanding on the accepted answer from Alex Hall:

From the Pydantic docs, it appears the call to update_forward_refs() is still required whether or not annotations is imported.

from typing import List
from pydantic import BaseModel

class Task(BaseModel):
    name: str
    subtasks: List['Task'] = []


Task.update_forward_refs()

or

# python3.7+
from __future__ import annotations
from typing import List
from pydantic import BaseModel

class Task(BaseModel):
    name: str
    subtasks: List[Task] = []


Task.update_forward_refs()

https://pydantic-docs.helpmanual.io/usage/postponed_annotations/#self-referencing-models

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM