[英]Python [pydantic] - Date validation
我想驗證日期的 json 輸入為 pydantic class,接下來,只需將文件注入 Mongo。
帶日期類型的簡單 class
class CustomerBase(BaseModel):
birthdate: date = None
使用電機與 Mongo 一起工作
數據庫配置:
from motor.motor_asyncio import AsyncIOMotorClient
DB = DB_CLIENT[CONF.get("databases", dict())["mongo"]["NAME"]]
2021 年 8 月 3 日 - 更新:
我做了以下調試測試,首先打印 class 以查看它是如何保存的,然后嘗試將其注入 Mongo。
所以輸入:
{ "birthdate": "2021-03-05"}
路由:
@customers_router.post("/", response_model=dict)
async def add_customer(customer: CustomerBase):
print(customer.dict())
>> {'birthdate': datetime.date(2021, 3, 5)}
await DB.customer.insert_one(customer.dict())
return {"test":1}
>>
File "./customers/routes.py", line 74, in add_customer
await DB.customer.insert_one(customer.dict())
File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.8/site-packages/pymongo/collection.py", line 698, in insert_one
self._insert(document,
File "/usr/local/lib/python3.8/site-packages/pymongo/collection.py", line 613, in _insert
return self._insert_one(
File "/usr/local/lib/python3.8/site-packages/pymongo/collection.py", line 602, in _insert_one
self.__database.client._retryable_write(
File "/usr/local/lib/python3.8/site-packages/pymongo/mongo_client.py", line 1498, in _retryable_write
return self._retry_with_session(retryable, func, s, None)
File "/usr/local/lib/python3.8/site-packages/pymongo/mongo_client.py", line 1384, in _retry_with_session
return self._retry_internal(retryable, func, session, bulk)
File "/usr/local/lib/python3.8/site-packages/pymongo/mongo_client.py", line 1416, in _retry_internal
return func(session, sock_info, retryable)
File "/usr/local/lib/python3.8/site-packages/pymongo/collection.py", line 590, in _insert_command
result = sock_info.command(
File "/usr/local/lib/python3.8/site-packages/pymongo/pool.py", line 699, in command
self._raise_connection_failure(error)
File "/usr/local/lib/python3.8/site-packages/pymongo/pool.py", line 683, in command
return command(self, dbname, spec, slave_ok,
File "/usr/local/lib/python3.8/site-packages/pymongo/network.py", line 120, in command
request_id, msg, size, max_doc_size = message._op_msg(
File "/usr/local/lib/python3.8/site-packages/pymongo/message.py", line 714, in _op_msg
return _op_msg_uncompressed(
bson.errors.InvalidDocument: cannot encode object: datetime.date(2021, 3, 5), of type: <class 'datetime.date'>
問題: 1.class 中的日期保存為生日: datetime.date(2021, 3, 5) 是預期的嗎? 2.問題肯定來自: ''' DB.customer.insert_one(customer.dict()) ''' 當我在 Class 中將日期類型更改為 str 時,它確實有效
2022 年 9 月 3 日更新:
按照湯姆的建議:添加了裝飾器和 parse_birthday function。 現在我可以記錄到 Mongo 但無法閱讀它。
class CustomerBase(BaseModel):
birthdate: datetime.date
@validator("birthdate", pre=True)
def parse_birthdate(cls, value):
return datetime.datetime.strptime(
value,
"%d/%m/%Y"
).date()
def dict(self, *args, **kwargs) -> 'DictStrAny':
for_mongo = kwargs.pop('for_mongo', False)
d = super().dict(*args, **kwargs)
if for_mongo:
for k, v in d.items():
if isinstance(v, datetime.date):
d[k] = datetime.datetime(
year=v.year,
month=v.month,
day=v.day,
)
return d
class CustomerOnDB(CustomerBase):
id_: str
分配數據(工作):輸入:{“birthdate”:“01/11/1978”}
@customers_router.post("/", response_model=dict )
async def add_customer(customer: CustomerBase):
customer_op = await DB.customer.insert_one(customer.dict(for_mongo=True))
if customer_op.inserted_id:
#customer_op.inserted_id -> is the str _id
await _get_customer_or_404(customer_op.inserted_id)
return { "id_": str(customer_op.inserted_id) }
嘗試閱讀時:
def validate_object_id(id_: str):
try:
_id = ObjectId(id_)
except Exception:
raise HTTPException(status_code=400)
return _id
@customers_router.get(
"/{id_}",
response_model=CustomerOnDB
)
async def get_customer_by_id(id_: ObjectId = Depends(validate_object_id)):
customer = await DB.customer.find_one({"_id": id_})
if customer:
customer["id_"] = str(customer["_id"])
return customer
else:
raise HTTPException(status_code=404, detail="Customer not found")
得到:
File "/usr/local/lib/python3.8/site-packages/fastapi/routing.py", line 126, in serialize_response
raise ValidationError(errors, field.type_)
pydantic.error_wrappers.ValidationError: 1 validation error for CustomerOnDB
response -> 0 -> birthdate
strptime() argument 1 must be str, not datetime.datetime (type=type_error)
我不確定您的問題是什么,因為您的CustomerBase
可以正常使用
{ "birthdate": "2021-03-05"}
這個輸入。
如果要解析%d/%m/%Y
日期,請使用驗證器和pre
參數對其進行解析。
class CustomerBase(BaseModel):
birthdate: date
@validator("birthdate", pre=True)
def parse_birthdate(cls, value):
return datetime.datetime.strptime(
value,
"%d/%m/%Y"
).date()
編輯:您添加了一條評論,提到了其他無法按預期工作的內容。 AFAIK mongo 不接受datetime.date
。 轉儲到 dict 或將類型更改為datetime.datetime
時,只需將其更改為datetime
。
例子
import datetime
from pydantic.main import BaseModel
class CustomerBase(BaseModel):
birthdate: datetime.date
def dict(self, *args, **kwargs) -> 'DictStrAny':
d = super().dict(*args, **kwargs)
for k, v in d.items():
if isinstance(v, datetime.date):
d[k] = datetime.datetime(
year=v.year,
month=v.month,
day=v.day,
)
return d
如果您需要這兩種功能
import datetime
from pydantic import validator
from pydantic.main import BaseModel
class CustomerBase(BaseModel):
birthdate: datetime.date
@validator("birthdate", pre=True)
def parse_birthdate(cls, value):
return datetime.datetime.strptime(
value,
"%d/%m/%Y"
).date()
def dict(self, *args, **kwargs) -> 'DictStrAny':
for_mongo = kwargs.pop('for_mongo', False)
d = super().dict(*args, **kwargs)
if for_mongo:
for k, v in d.items():
if isinstance(v, datetime.date):
d[k] = datetime.datetime(
year=v.year,
month=v.month,
day=v.day,
)
return d
>>> c = CustomerBase(**{"birthdate": "03/05/2021"})
>>> c.dict()
>>> {'birthdate': datetime.date(2021, 5, 3)}
>>> c.dict(for_mongo=True)
>>> {'birthdate': datetime.datetime(2021, 5, 3, 0, 0)}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.