Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pydantic model for array of jsons

I am using FastAPI to write a web service. It is good and fast.

FastAPI is using pydantic models to validate input and output data, everything is good but when I want to declare a nested model for array of jsons like below:

[
   {
      "name": "name1",
      "family": "family1"
   },
   {
      "name": "name2",
      "family": "family2"
   }
]

I get empty response.

I think there is a problem with my model which is:

class Test(BaseModel):
    name: str
    family: str
    class Config:
        orm_mode = True

class Tests(BaseModel):
    List[Test]
    class Config:
        orm_mode = True

So, my question is how should I write a model for array of jsons?

like image 972
kamal Avatar asked Apr 29 '20 08:04

kamal


People also ask

What is a pydantic model?

Pydantic models are structures that ingest the data, parse it and make sure it conforms to the fields' constraints defined in it. Let's start with a simple example, where we define a Person class that has two fields without any constraints: first_name and last_name . Just like dataclasses, we use type annotations.

How do you use pydantic in Python?

Defining an object in pydantic is as simple as creating a new class which inherits from the BaseModel . When you create a new object from the class, pydantic guarantees that the fields of the resultant model instance will conform to the field types defined on the model.

What is pydantic Constr?

constr is a specific type that give validation rules regarding this specific type. You have equivalent for all classic python types.


1 Answers

Update (26/09/2020)

In Python 3.9 (not yet released), you can do the same as below but with the built-in list generic type (which is always in scope) rather than needing to import the capitalized List type from typing, e.g.

@app.get("/tests", response_model=list[Test])

The issue here is that you are trying to create a pydantic model where it is not needed. If you want to serialize/deserialize a list of objects, just wrap your singular model in a List[] from python's builtin typing module. There is no need to try to create a plural version of your object with a pydantic BaseModel (and as you can see, it does not work anyway).

With that said, the simplest way to do what you want is to just specify a List[Test] at any point where you need a list of Tests, e.g.

from typing import List

from fastapi import FastAPI
from pydantic import BaseModel


existing_tests = [
    {
        "name": "name1",
        "family": "family1"
    },
    {
        "name": "name2",
        "family": "family2"
    }
]


class Test(BaseModel):
    name: str
    family: str

    class Config:
        orm_mode = True


app = FastAPI()


@app.get("/tests", response_model=List[Test])
async def fetch_tests():
    return existing_tests


@app.post("/tests")
async def submit_tests(new_tests: List[Test]):
    print(new_tests)

But of course if you find yourself repeatedly (or only) specifying Test as a list, you can of course just assign this to a variable and then use that variable where needed, like so:

Tests = List[Test]

@app.get("/tests", response_model=Tests)
async def fetch_tests():
    return existing_tests

@app.post("/tests")
async def submit_tests(new_tests: Tests):
    print(new_tests)

I think the first option is probably slightly clearer in your code though, and unless you are specifying List[Test] many times, using a variable for this purpose is probably not worth the extra layer of indirection.

like image 153
acnebs Avatar answered Sep 29 '22 00:09

acnebs