English 中文(简体)
快速通货模式有条件呼吁
原标题:Conditional call of a FastAPI Model

我有一个多兰快车,与莫戈亚行连接。 我在MongoDB的文件用两种现有语文复制,并以这种方式编排(简单的例子):


{
  "_id": xxxxxxx,
  "en": { 
          "title": "Drinking Water Composition",
          "description": "Drinking water composition expressed in... with pesticides.",
          "category": "Water", 
          "tags": ["water","pesticides"] 
         },
  "fr": { 
          "title": "Composition de l eau de boisson",
          "description": "Composition de l eau de boisson exprimée en... présence de pesticides....",
          "category": "Eau", 
          "tags": ["eau","pesticides"] 
         },  
}

因此,我实施了两个模型:<代码>DatasetFR和DatasetEN。 关于<代码><<>>>/代码>和<代码>>> 每一平方的标/代码>的具体外部模型(Enum)。

class DatasetFR(BaseModel):
    title:str
    description: str
    category: CategoryFR
    tags: Optional[List[TagsFR]]

# same for DatasetEN chnaging the lang tag to EN 

在路线定义中,我强迫语言参数宣布相应的模型并获得相应的验证。


@router.post("?lang=fr", response_description="Add a dataset")
async def create_dataset(request:Request, dataset: DatasetFR = Body(...), lang:str="fr"):
    ...
    return JSONResponse(status_code=status.HTTP_201_CREATED, content=created_dataset)

@router.post("?lang=en", response_description="Add a dataset")
async def create_dataset(request:Request, dataset: DatasetEN = Body(...), lang:str="en"):
    ...
    return JSONResponse(status_code=status.HTTP_201_CREATED, content=created_dataset)

但是,这似乎与将相应模式称作。

或者,如果我们能够创建一种家长模型数据集,采用兰经理论,检索儿童模型数据集。

这将令人难以置信地方便地建造我的普森通道和我模式的号召,并用两种文字在数学上分割......

最佳回答

Option 1

A solution would be the following. Define lang as Query paramter and add a regular expression that the parameter should match. In your case, that would be ^(fr|en)$, meaning that only fr or en would be valid inputs. Thus, if no match was found, the request would stop there and the client would receive a "string does not match regex..." error.

Next, define the body parameter as a generic type of dict and declare it as Body field; thus, instructing FastAPI to expect a JSON body.

之后,创立了您的<代码>models的字典。 您可使用lang属性查询模型。 一旦找到相应的<代码>model,try to parse the JSON body using models[lang].parse_obj(one) (equivalent to using models[lang](**one))。 如果没有<代码>ValidationError,你知道由此产生的<代码>model例有效。 否则,将

如果您也希望<代码>FR和EN成为有效lang的数值,则通过<>^(i)(代码>fren)$加以调整,以确保在研究模型时将lang<>>>/code>改为较低(i.e.,models[lang.down()].parse_obj(本人)

import  pydantic 
from fastapi import FastAPI, Response, status, Body, Query
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder

models = {"fr": DatasetFR, "en": DatasetEN}

@router.post("/", response_description="Add a dataset")
async def create_dataset(body: dict = Body(...), lang: str = Query(..., regex="^(fr|en)$")):
    try:
        model = models[lang].parse_obj(body)
    except pydantic.ValidationError as e:
        return Response(content=e.json(), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, media_type="application/json")

    return JSONResponse(content=jsonable_encoder(dict(model)), status_code=status.HTTP_201_CREATED)

Update

Since the two models have identical attributes (i.e., title and description), you could define a parent model (e.g., Dataset) with those two attributes, and have DatasetFR and DatasetEN models inherit those.

class Dataset(BaseModel):
    title:str
    description: str
    
class DatasetFR(Dataset):
    category: CategoryFR
    tags: Optional[List[TagsFR]]
    
class DatasetEN(Dataset):
    category: CategoryEN
    tags: Optional[List[TagsEN]]

Additionally, it might be a better approach to move the logic from inside the route to a dependency function and have it return the model, if it passes the validation; otherwise, raise an HTTPException, as also demonstrated by @tiangolo. You can use jsonable_encoder, which is internally used by FastAPI, to encode the validation errors() (the same function can also be used when returning the JSONResponse).

from fastapi.exceptions import HTTPException
from fastapi import Depends

models = {"fr": DatasetFR, "en": DatasetEN}

async def checker(body: dict = Body(...), lang: str = Query(..., regex="^(fr|en)$")):
    try:
        model = models[lang].parse_obj(body)
    except pydantic.ValidationError as e:
        raise HTTPException(detail=jsonable_encoder(e.errors()), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)

    return model
        
@router.post("/", response_description="Add a dataset")
async def create_dataset(model: Dataset = Depends(checker)):    
    return JSONResponse(content=jsonable_encoder(dict(model)), status_code=status.HTTP_201_CREATED)

Option 2

另一种做法是,采用单一Pydantic模型(Dataset),并定制validators > 编码>。 您也可将<条码>-<>/条码>界定为<条码>的一部分,因此无需将其列为查询参数。 如https://stackoverflow.com/a/43634746>,,请使用<条码>。 Enum 类别,这样,如果在<代码>上存在价值,你就可以有效地核对。 Enum;并且有密码,可使用<条码><>/条码>迅速研究<条码>。 在<代码>tags的情况下,核实清单中的每一要素均为有效,使用.isset.subset,描述为,,其中将被抓获并用于填满>>>(见“说明”一节lang<>/code>,则作为有效投入书写的代码,可调整<代码>regex/code>。

P.S. You don t even need to use Enum with this approach. Instead, populate each set below with the permitted values. For instance, categories_FR = {"Eau"} categories_EN = {"Water"} tags_FR = {"eau", "pesticides"} tags_EN = {"water", "pesticides"}. Additionally, if you would like not to use regex, but rather have a custom validation error for lang attribute as well, you could add it in the same validator decorator and perform validation similar (and previous) to the other two fields.

from pydantic import validator

categories_FR = set(item.value for item in CategoryFR) 
categories_EN = set(item.value for item in CategoryEN) 
tags_FR = set(item.value for item in TagsFR) 
tags_EN = set(item.value for item in TagsEN) 
cats = {"fr": categories_FR, "en": categories_EN}
tags = {"fr": tags_FR, "en": tags_EN}

def raise_error(values):
    raise ValueError(f value is not a valid enumeration member; permitted: {values} )

class Dataset(BaseModel):
    lang: str = Body(..., regex="^(fr|en)$")
    title: str
    description: str
    category: str
    tags: List[str]

    @validator("category", "tags")
    def validate_atts(cls, v, values, field):
        lang = values.get( lang )
        if lang:
            if field.name == "category":
                if v not in cats[lang]: raise_error(cats[lang])
            elif field.name == "tags":
                if not set(v).issubset(tags[lang]): raise_error(tags[lang])
        return v

        
@router.post("/", response_description="Add a dataset")
async def create_dataset(model: Dataset): 
    return JSONResponse(content=jsonable_encoder(dict(model)), status_code=status.HTTP_201_CREATED)
Update

请注意,在Pydantic V2中,@validator已被折旧,取而代之的是@field_validator。 请查阅,以便了解更多细节和实例。

Option 3

另一种做法是使用Discriminated Unions,详见

根据文件:

When Union is used with multiple submodels, you sometimes know exactly which submodel needs to be checked and validated and want to enforce this. To do that you can set the same field - let s call it my_discriminator - in each of the submodels with a discriminated value, which is one (or many) Literal value(s). For your Union, you can set the discriminator in its value: Field(discriminator= my_discriminator ).

成立受歧视的工会具有许多好处:

  • validation is faster since it is only attempted against one model
  • only one explicit error is raised in case of failure
  • the generated JSON schema implements the associated OpenAPI specification
问题回答

答案有两部分(API电话和数据结构)。

for the API call, you could separate them into 2 routes like /api/v1/fr/... and /api/v1/en/... (separating ressource representation!) and play with fastapi.APIRouter to declare the same route twice but changing for each route the validation schema by the one you want to use.

首先,你可以宣布一个共同基地,作为ABC和ABCEnum。

from abc import ABC
from pydantic import BaseModel

class MyModelABC(ABC, BaseModel):
    attribute1: MyEnumABC

class MyModelFr(MyModelABC):
    attribute1: MyEnumFR

class MyModelEn(MyModelABC):
    attribute1: MyEnumEn

然后,你可以选择一个班级工厂运输路线的准确模式:

my_class_factory: dict[str, MyModelABC] = {
    "fr": MyModelFr,
    "en": MyModelEn, 
}

最后,你可以通过一个路运厂铺铺你的道路:

def generate_language_specific_router(language: str, ...) -> APIRouter:
    router = APIRouter(prefix=language)
    MySelectedModel: MyModelABC = my_class_factory[language]

    @router.post("/")
    def post_something(my_model_data: MySelectedModel):
        # My internal logic
    return router

大约第二部分(内部计算和数据储存),国际化往往通过散图进行。

The standard python Library gettext/a。 可进行调查

Otherwise, the original language can be explicitely used as the key/hash and then map translations to it (also including the original language if you want to have consistency in your calls).

It can look like:

dictionnary_of_babel = {
    "word1": {
        "en": "word1",
        "fr": "mot1",
    },
    "word2": {
        "en": "word2",
    },
    "Drinking Water Composition": {
        "en": "Drinking Water Composition",
        "fr": "Composition de l eau de boisson",
    },
}

my_arbitrary_object = {
    "attribute1": "word1",
    "attribute2": "word2",
    "attribute3": "Drinking Water Composition",
}

my_translated_object = {}
for attribute, english_sentence in my_arbitrary_object.items():
    if "fr" in dictionnary_of_babel[english_sentence].keys():
        my_translated_object[attribute] = dictionnary_of_babel[english_sentence]["fr"]
    else:
        my_translated_object[attribute] = dictionnary_of_babel[english_sentence]["en"]  # ou sans "en"

expected_translated_object = {
    "attribute1": "mot1",
    "attribute2": "word2",
    "attribute3": "Composition de l eau de boisson",
}

assert expected_translated_object == my_translated_object

<><>>>> 该代码应为。

A. 关于地方自治的提案 如果我们不希望有一个单独的翻译表,则非行的代表性可以是<条码>数据结构。 例如:

# normal:
my_attribute: "sentence"

# internationalized
my_attribute_internationalized: {
    sentence: {
        original_lang: "sentence"
        lang1: "sentence_lang1",
        lang2: "sentence_lang2",
    }
}

简便的文字是界定一个匿名功能_(<>,该功能将翻译成文如下:

CURRENT_MODULE_LANG = "fr"

def _(original_string: str) -> str:
    """Switch from original_string to translation"""
    return dictionnary_of_babel[original_string][CURRENT_MODULE_LANG]

因此,需要翻译:

>>> print(_("word 1"))
"mot 1"

您可在关于internationalization-in-python-code

For static translation (for example a website or a documentation), you can use .po files and editors like poedit (See the french translation of python docs for a practical usecase)!





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签