简体   繁体   中英

How to use values from list to validate some calculations in pydantic BaseModel?

I'm using Pydantic root_validator to perform some calculations in my model:

class ProductLne(BaseModel):
    qtt_line: float = 0.00
    prix_unite: float = 0.00
    so_total_ht: float = 0.00
    
    class Config:
        validate_assignment = True

    @root_validator()
    def calculat_so_totals(cls, values):
      values["so_total_ht"] = values.get("qtt_line")*values.get("prix_unite")
    
    return values

class Bon(BaseModel):
    articles: List[ProductLne] = []
    total_ht: float = 0.00

    class Config:
        validate_assignment = True

    @root_validator()
    def set_total_ht(cls, values):
        for item in values.get('articles'):
            values['total_ht'] += item.so_total_ht
        return values

some data

 item_line1 = ProductLne(qtt_line=10, prix_unite=10.00)
 item_line2 = ProductLne(qtt_line=10, prix_unite=12.00)
 bon1 = Bon()
 bon1.articles.append(item_line1)
 bon1.articles.append(item_line2)

when run

 print(bon1.total_ht)

i get: 0.0, O.OO Iwant 220

How to make this function return the correct values?

I found your issue. It's because you are trying to access data that doesn't exist on the cls and how you were accessing the data from the values was wrong. First, You have to pass data through the ProductLne at some point and the Bon . So I changed your code to set the values for ProductLne on initialization, then just initialize it in the validator on the Bon initialization. Then just run Bon() and I believe this is what you are trying to accomplish. You can still pass data in through a script, I just don't know what your script looks like. Example (simplified):

class ProductLne(BaseModel):
    qtt_line: float = 1.0
    so_total_ht: float = 1.0

    @root_validator()
    def calculat_so_totals(cls, values):
        values["so_total_ht"] = values.get("qtt_line")
        return values


class Bon(BaseModel):
    articles: List[ProductLne] = []
    total_ht: float = 0.0

    @root_validator()
    def set_total_ht(cls, values):
        product_line = ProductLne()
        values["articles"].append(product_line)
        for item in values.get("articles"):
           values["total_ht"] += item.qtt_line
        return values

I do not know if this is good why, but i get what i want

from pydantic import BaseModel, root_validator, Field
from typing import List
from typing import TYPE_CHECKING, Union
if TYPE_CHECKING:
    from pydantic.typing import DictStrAny


class PropertyBaseModel(BaseModel):

@classmethod
def get_properties(cls):
    return [
        prop for prop in dir(cls)
        if isinstance(getattr(cls, prop), property) and prop not in ("__values__", "fields")
    ]

def dict(self, *args, **kwargs) -> 'DictStrAny':
    self.__dict__.update({prop: getattr(self, prop) for prop in self.get_properties()})

    return super().dict(*args, **kwargs)


class ProductLne(PropertyBaseModel):
    prix: float = 0.00
    qtt_line: float = 0.0

    @property
    def so_total_ht(self) -> float:
        return self.qtt_line * self.prix


class Bon(BaseModel):
    articles: List[ProductLne] = []

    @property
    def total_ht(self) -> float:
        bla = 0.00
        for item in self.articles:
            bla += item.so_total_ht
    return bla


item_line1 = ProductLne(prix=10.00,qtt_line=10)
item_line2 = ProductLne(prix=12.00,qtt_line=10)

print(item_line1.so_total_ht)
print(item_line2.so_total_ht)

bon1 = Bon()
bon1.articles.append(item_line1)
bon1.articles.append(item_line2)
print(bon1.total_ht) #220

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