How to set range and value out of range in Pydantic field using FastAPI?
Asked Answered
I

2

6

So I have the following line of code:

item: Optional[int] = Field(None, ge=1, le=168)

and I would like to have possibility to set -1 value as well. So, I need to exclude zero values, but I would like to allow a -1 value and values from 1 to 168.

Is there any way to do this?

Interdigitate answered 27/7, 2022 at 11:17 Comment(4)
I am not sure if I understand your question corrently but ge means greater or equals to and le means less than or equals to. So if you want a custom range, you need to change these params accordingly. For example Field(None, ge=-1, le=168)Surculose
it so than I need to exclude zero value so it will look like '''-1''' and from 1 to 168Interdigitate
You could extend the range down to -1, and then add a custom Pydantic validator checking that it is not 0?Remise
yeap, I thought about it, but hope that there is prettier solution for this problemInterdigitate
Q
9

You could specify the range from -1 to 168 and also have a custom Pydantic validator to check whether or not the value is equal to 0. If so, raise ValueError. If the Pydantic model was instead used to define query parameters for the endpoint (using Depends()), please have a look at this answer.

Example

from fastapi import FastAPI
from typing import Optional
from pydantic import Field, BaseModel, validator

app = FastAPI()

class Foo(BaseModel):
    item: Optional[int] = Field(None, ge=-1, le=168)

    @validator('item')
    def prevent_zero(cls, v):
        if v == 0: 
            raise ValueError('ensure this value is not 0')
        return v
 
@app.post("/")
def submit(foo: Foo):
    return foo

Update

Please note that in Pydantic V2, @validator has been deprecated and was replaced by @field_validator. Please have a look at this answer for more details and examples.

Quintinquintina answered 28/7, 2022 at 10:30 Comment(1)
Is there really no other way (there was once a regex attribute, but it seems to have been dropped with v >2)?Deduct
B
1

I've been trying to define "-1 or > 0" and I got very close with this:

from typing import Union, Literal
from pydantic import PositiveInt
from pydantic.fields import Field
from pydantic_settings import BaseSettings

class MyClass(BaseSettings):
  item: Union[Literal[-1], PositiveInt] = Field(union_mode=“left_to_right”, default=-1)

I believe the type definition alone works as desired (need to do a little more testing), but the pydantic_settings from an environment variable aspect does not.

The problem is that this is using pydantic settings and applying this from an environment variable, which are always 'string' type at the point they're matched against the type definition here. So it's technically Literal["-1"] and this fails.

Otherwise, this appears to express what I want without a custom validator...

Brannen answered 11/1 at 3:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.