{"id":2116,"date":"2024-11-16T16:36:00","date_gmt":"2024-11-16T08:36:00","guid":{"rendered":"http:\/\/blog.xtaa.cn\/?p=2116"},"modified":"2024-11-16T19:03:17","modified_gmt":"2024-11-16T11:03:17","slug":"pydantic%e5%ba%93-%e6%95%b0%e6%8d%ae%e9%aa%8c%e8%af%81%e5%92%8c%e8%ae%be%e7%bd%ae%e7%ae%a1%e7%90%86","status":"publish","type":"post","link":"http:\/\/blog.xtaa.cn\/index.php\/2024\/11\/16\/pydantic%e5%ba%93-%e6%95%b0%e6%8d%ae%e9%aa%8c%e8%af%81%e5%92%8c%e8%ae%be%e7%bd%ae%e7%ae%a1%e7%90%86\/","title":{"rendered":"Pydantic\u5e93-\u6570\u636e\u9a8c\u8bc1\u548c\u8bbe\u7f6e\u7ba1\u7406"},"content":{"rendered":"\n<p>\u5728\u5904\u7406\u6765\u81ea\u7cfb\u7edf\u5916\u90e8\u7684\u6570\u636e\uff0c\u5982API\u3001\u7ec8\u7aef\u7528\u6237\u8f93\u5165\u6216\u5176\u4ed6\u6765\u6e90\u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u7262\u8bb0\u5f00\u53d1\u4e2d\u7684\u4e00\u6761\u57fa\u672c\u539f\u5219\uff1a\u201c\u6c38\u8fdc\u4e0d\u8981\u76f8\u4fe1\u7528\u6237\u7684\u8f93\u5165\u201d\u3002<\/p>\n\n\n\n<p>\u56e0\u6b64\uff0c\u6211\u4eec\u5fc5\u987b\u5bf9\u8fd9\u4e9b\u6570\u636e\u8fdb\u884c\u4e25\u683c\u7684\u68c0\u67e5\u548c\u9a8c\u8bc1\uff0c\u786e\u4fdd\u5b83\u4eec\u88ab\u9002\u5f53\u5730\u683c\u5f0f\u5316\u548c\u6807\u51c6\u5316\u3002\u8fd9\u6837\u505a\u7684\u76ee\u7684\u662f\u4e3a\u4e86\u786e\u4fdd\u8fd9\u4e9b\u6570\u636e\u7b26\u5408\u6211\u4eec\u7684\u7a0b\u5e8f\u6240\u9700\u7684\u8f93\u5165\u89c4\u8303\uff0c\u4ece\u800c\u4fdd\u969c\u9879\u76ee\u80fd\u591f\u6b63\u786e\u4e14\u9ad8\u6548\u5730\u8fd0\u884c\u3002<\/p>\n\n\n\n<p>\u4e3a\u4ec0\u4e48\u4f7f\u7528 Python \u7684 Pydantic \u5e93\uff1f<br>Pydantic \u662f\u4e00\u4e2a\u5728 Python \u4e2d\u7528\u4e8e\u6570\u636e\u9a8c\u8bc1\u548c\u89e3\u6790\u7684\u7b2c\u4e09\u65b9\u5e93\uff0c\u5b83\u73b0\u5728\u662f Python \u4f7f\u7528\u6700\u5e7f\u6cdb\u7684\u6570\u636e\u9a8c\u8bc1\u5e93\u3002<\/p>\n\n\n\n<p>\u5b83\u5229\u7528\u58f0\u660e\u5f0f\u7684\u65b9\u5f0f\u5b9a\u4e49\u6570\u636e\u6a21\u578b\u548cPython \u7c7b\u578b\u63d0\u793a\u7684\u5f3a\u5927\u529f\u80fd\u6765\u6267\u884c\u6570\u636e\u9a8c\u8bc1\u548c\u5e8f\u5217\u5316\uff0c\u4f7f\u60a8\u7684\u4ee3\u7801\u66f4\u53ef\u9760\u3001\u66f4\u53ef\u8bfb\u3001\u66f4\u7b80\u6d01\u4e14\u66f4\u6613\u4e8e\u8c03\u8bd5\u3002\u3002<br>\u5b83\u8fd8\u53ef\u4ee5\u4ece\u6a21\u578b\u751f\u6210 JSON \u67b6\u6784\uff0c\u63d0\u4f9b\u4e86\u81ea\u52a8\u751f\u6210\u6587\u6863\u7b49\u529f\u80fd\uff0c\u4ece\u800c\u8f7b\u677e\u4e0e\u5176\u4ed6\u5de5\u5177\u96c6\u6210\u3002<\/p>\n\n\n\n<p><br>Pydantic \u7684\u4e00\u4e9b\u4e3b\u8981\u7279\u6027<br>\u6613\u7528\u6027<\/p>\n\n\n\n<p>Pydantic \u4f7f\u7528\u8d77\u6765\u7b80\u5355\u76f4\u89c2\uff0c\u9700\u8981\u6700\u5c11\u7684\u6837\u677f\u4ee3\u7801\u548c\u914d\u7f6e\u3002\u5b83\u9002\u7528\u4e8e\u8bb8\u591a\u6d41\u884c\u7684 IDE \u548c\u9759\u6001\u5206\u6790\u5de5\u5177\uff0c\u4f8b\u5982 PyCharm\u3001VS Code\u3001mypy \u7b49\u3002Pydantic \u53ef\u4ee5\u8f7b\u677e\u4e0e\u5176\u4ed6\u6d41\u884c\u7684 Python \u5e93\uff08\u5982 Flask\u3001Django\u3001FastAPI \u548c SQLAlchemy\uff09\u96c6\u6210\uff0c\u4f7f\u5176\u6613\u4e8e\u5728\u73b0\u6709\u9879\u76ee\u4e2d\u4f7f\u7528\u3002<\/p>\n\n\n\n<p>\u7c7b\u578b\u6ce8\u89e3<\/p>\n\n\n\n<p>Pydantic \u4f7f\u7528\u7c7b\u578b\u6ce8\u89e3\u6765\u5b9a\u4e49\u6a21\u578b\u7684\u5b57\u6bb5\u7c7b\u578b,\u4ee5\u786e\u4fdd\u786e\u4fdd\u6570\u636e\u7b26\u5408\u9884\u671f\u7684\u7c7b\u578b\u548c\u683c\u5f0f\u3002\u4f60\u53ef\u4ee5\u4f7f\u7528Python \u5185\u7f6e\u7684\u7c7b\u578b\u3001\u81ea\u5b9a\u4e49\u7c7b\u578b\u6216\u8005\u5176\u4ed6Pydantic \u63d0\u4f9b\u7684\u9a8c\u8bc1\u7c7b\u578b\u3002<\/p>\n\n\n\n<p>\u6570\u636e\u9a8c\u8bc1\uff0c\u7528\u6237\u53cb\u597d\u7684\u9519\u8bef<\/p>\n\n\n\n<p>Pydantic \u81ea\u52a8\u6839\u636e\u6a21\u578b\u5b9a\u4e49\u8fdb\u884c\u6570\u636e\u9a8c\u8bc1\u3002\u5b83\u4f1a\u68c0\u67e5\u5b57\u6bb5\u7684\u7c7b\u578b\u3001\u957f\u5ea6\u3001\u8303\u56f4\u7b49\uff0c\u5e76\u81ea\u52a8\u62a5\u544a\u9a8c\u8bc1\u9519\u8bef\uff0cPydantic \u4f1a\u63d0\u4f9b\u4fe1\u606f\u4e30\u5bcc\u4e14\u53ef\u8bfb\u7684\u9519\u8bef\u6d88\u606f\uff0c\u5305\u62ec\u9519\u8bef\u7684\u4f4d\u7f6e\u3001\u7c7b\u578b\u548c\u8f93\u5165\u3002\u4f60\u53ef\u4ee5\u4f7f\u7528 ValidationError \u5f02\u5e38\u6765\u6355\u83b7\u9a8c\u8bc1\u9519\u8bef\u3002<\/p>\n\n\n\n<p>\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316<\/p>\n\n\n\n<p>\u5e8f\u5217\u5316\u662f\u5c06\u590d\u6742\u6570\u636e\u7ed3\u6784\uff08\u5982\u5bf9\u8c61\u3001\u6570\u7ec4\u3001\u5b57\u5178\u7b49\uff09\u8f6c\u6362\u4e3a\u7b80\u5355\u6570\u636e\u683c\u5f0f\uff08\u5982\u5b57\u7b26\u4e32\u6216\u5b57\u8282\u6d41\uff09\u7684\u8fc7\u7a0b\u3002\u8fd9\u6837\u505a\u662f\u4e3a\u4e86\u4fbf\u4e8e\u5b58\u50a8\u6216\u4f20\u8f93\u3002\u53cd\u5e8f\u5217\u5316\u662f\u76f8\u53cd\u7684\u8fc7\u7a0b\uff0c\u5c06\u7b80\u5355\u6570\u636e\u683c\u5f0f\u8fd8\u539f\u4e3a\u590d\u6742\u6570\u636e\u7ed3\u6784\u3002Pydantic \u63d0\u4f9b\u4e86\u4ece\u5404\u79cd\u6570\u636e\u683c\u5f0f\uff08\u4f8b\u5982 JSON\u3001\u5b57\u5178\uff09\u5230\u6a21\u578b\u5b9e\u4f8b\u7684\u8f6c\u6362\u529f\u80fd\u3002\u5b83\u53ef\u4ee5\u81ea\u52a8\u5c06\u8f93\u5165\u6570\u636e\u89e3\u6790\u6210\u6a21\u578b\u5b9e\u4f8b\uff0c\u5e76\u4fdd\u7559\u7c7b\u578b\u5b89\u5168\u6027\u548c\u9a8c\u8bc1\u89c4\u5219\u3002<\/p>\n\n\n\n<p>\u6027\u80fd\u9ad8<\/p>\n\n\n\n<p>Pydantic \u7684\u6838\u5fc3\u9a8c\u8bc1\u903b\u8f91\u662f\u7528 Rust \u7f16\u5199\u7684\uff0c\u4f7f\u5176\u6210\u4e3a Python \u4e2d\u6700\u5feb\u7684\u6570\u636e\u9a8c\u8bc1\u5e93\u4e4b\u4e00\u3002\u5b83\u8fd8\u652f\u6301\u5ef6\u8fdf\u9a8c\u8bc1\u548c\u7f13\u5b58\uff0c\u4ee5\u63d0\u9ad8\u6548\u7387\u3002<\/p>\n\n\n\n<p><br>\u8981\u4f7f\u7528\u53ef\u4ee5\u76f4\u63a5\u5b89\u88c5<\/p>\n\n\n\n<p>pip install pydantic<\/p>\n\n\n\n<p>Pydantic \u4f7f\u7528\u4f8b\u5b50<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from datetime import datetime\n\nfrom pydantic import BaseModel, PositiveInt\n\n\nclass User(BaseModel):\n    id: int  #id \u7684\u7c7b\u578b\u662f int \uff1b\u4ec5\u6ce8\u91ca\u58f0\u660e\u544a\u77e5 Pydantic \u8be5\u5b57\u6bb5\u662f\u5fc5\u9700\u7684\u3002\u5982\u679c\u53ef\u80fd\uff0c\u5b57\u7b26\u4e32\u3001\u5b57\u8282\u6216\u6d6e\u70b9\u6570\u5c06\u88ab\u5f3a\u5236\u8f6c\u6362\u4e3a\u6574\u6570\uff1b\u5426\u5219\u5c06\u5f15\u53d1\u5f02\u5e38\u3002\n    name: str = 'John Doe'  #name \u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\uff1b\u56e0\u4e3a\u5b83\u6709\u9ed8\u8ba4\u503c\uff0c\u6240\u4ee5\u4e0d\u5fc5\u9700\u3002\n    signup_ts: datetime | None  #signup_ts \u662f\u4e00\u4e2a\u5fc5\u586b\u7684 datetime \u5b57\u6bb5\uff0c\u4f46\u503c None \u53ef\u4ee5\u63d0\u4f9b\uff1bPydantic \u5c06\u5904\u7406 Unix \u65f6\u95f4\u6233\u6574\u6570\uff08\u4f8b\u5982 1496498400 \uff09\u6216\u8868\u793a\u65e5\u671f\u548c\u65f6\u95f4\u7684\u5b57\u7b26\u4e32\u3002\n    tastes: dict&#91;str, PositiveInt]  #tastes \u662f\u4e00\u4e2a\u952e\u4e3a\u5b57\u7b26\u4e32\u4e14\u503c\u4e3a\u6b63\u6574\u6570\u7684\u5b57\u5178\u3002 PositiveInt \u7c7b\u578b\u662f Annotated&#91;int, annotated_types.Gt(0)] \u7684\u7b80\u5199\u3002\n\n\nexternal_data = {\n    'id': 123,\n    'signup_ts': '2019-06-01 12:22',  #\u8fd9\u91cc\u7684\u8f93\u5165\u662f\u4e00\u4e2a ISO8601 \u683c\u5f0f\u7684\u65e5\u671f\u65f6\u95f4\uff0cPydantic \u5c06\u628a\u5b83\u8f6c\u6362\u4e3a\u4e00\u4e2a datetime \u5bf9\u8c61\u3002\n    'tastes': {\n        'wine': 9,\n        b'cheese': 7,  #\u5173\u952e\u5728\u8fd9\u91cc\u662f bytes \uff0c\u4f46 Pydantic \u4f1a\u8d1f\u8d23\u5c06\u5176\u5f3a\u5236\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002\n        'cabbage': '1',  #\u540c\u6837\u5730\uff0cPydantic \u4f1a\u5c06\u5b57\u7b26\u4e32 '1' \u5f3a\u5236\u8f6c\u6362\u4e3a\u6574\u6570 1\n    },\n}\n\nuser = User(**external_data)  #\u8fd9\u91cc\u901a\u8fc7\u5c06\u5916\u90e8\u6570\u636e\u4f5c\u4e3a\u5173\u952e\u5b57\u53c2\u6570\u4f20\u9012\u7ed9 User \u6765\u521b\u5efa User \u7684\u5b9e\u4f8b\n\nprint(user.id)  #\u6211\u4eec\u53ef\u4ee5\u5c06\u5b57\u6bb5\u4f5c\u4e3a\u6a21\u578b\u7684\u5c5e\u6027\u6765\u8bbf\u95ee\n#> 123\nprint(user.model_dump())  #\u6211\u4eec\u53ef\u4ee5\u5c06\u6a21\u578b\u8f6c\u6362\u4e3a\u5e26\u6709 model_dump() \u7684\u5b57\u5178\n\"\"\"\n{\n    'id': 123,\n    'name': 'John Doe',\n    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),\n    'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1},\n}\n\"\"\"<\/code><\/pre>\n\n\n\n<p>\u5982\u679c\u9a8c\u8bc1\u5931\u8d25\uff0cPydantic \u4f1a\u5f15\u53d1\u4e00\u4e2a\u9519\u8bef\u5e76\u8be6\u7ec6\u8bf4\u660e\u54ea\u91cc\u51fa\u9519\u4e86\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># continuing the above example...\n\nfrom pydantic import ValidationError\n\n\nclass User(BaseModel):\n    id: int\n    name: str = 'John Doe'\n    signup_ts: datetime | None\n    tastes: dict&#91;str, PositiveInt]\n\n\nexternal_data = {'id': 'not an int', 'tastes': {}}  \n\ntry:\n    User(**external_data)  \nexcept ValidationError as e:\n    print(e.errors())\n    \"\"\"\n    &#91;\n        {\n            'type': 'int_parsing',\n            'loc': ('id',),\n            'msg': 'Input should be a valid integer, unable to parse string as an integer',\n            'input': 'not an int',\n            'url': 'https:\/\/pydantic.com.cn\/errors\/validation_errors#int_parsing',\n        },\n        {\n            'type': 'missing',\n            'loc': ('signup_ts',),\n            'msg': 'Field required',\n            'input': {'id': 'not an int', 'tastes': {}},\n            'url': 'https:\/\/pydantic.com.cn\/errors\/validation_errors#missing',\n        },\n    ]\n    \"\"\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h_652791602_1\">\u7b80\u5355\u89e3\u91ca<\/h2>\n\n\n\n<p>Pydantic \u5141\u8bb8\u4f60\u5b9a\u4e49\u6570\u636e\u6a21\u578b\uff0c\u8fd9\u4e9b\u6a21\u578b\u4f1a\u81ea\u52a8\u9a8c\u8bc1\u8f93\u5165\u6570\u636e\u7684\u7ed3\u6784\u548c\u7c7b\u578b\u3002\u4f60\u53ea\u9700\u5b9a\u4e49\u4e00\u4e2a\u7c7b\uff0c\u7528 Python \u7684\u7c7b\u578b\u63d0\u793a\u6807\u6ce8\u5176\u5b57\u6bb5\uff0cPydantic \u5c31\u4f1a\u4e3a\u4f60\u5904\u7406\u9a8c\u8bc1\u548c\u5e8f\u5217\u5316\u3002\u4e0e\u4f7f\u7528JSON Schema\u6216OpenAPI\u8fdb\u884c\u624b\u52a8\u9a8c\u8bc1\u76f8\u6bd4\uff0c\u8fd9\u5927\u5927\u7b80\u5316\u4e86\u6570\u636e\u9a8c\u8bc1\u8fc7\u7a0b\u3002\u540c\u65f6\uff0cPydantic \u4e5f\u63d0\u4f9b\u4e86\u5f3a\u5927\u7684\u6570\u636e\u8f6c\u6362\u80fd\u529b\uff0c\u80fd\u5c06\u590d\u6742\u6570\u636e\u7ed3\u6784\uff08\u5982 JSON\u3001\u5b57\u5178\uff09\u8f7b\u6613\u8f6c\u6362\u4e3aPython\u5bf9\u8c61\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h_652791602_2\">\u573a\u666f\uff1aAPI \u53c2\u6570\u9a8c\u8bc1\u548c\u8f6c\u6362\u5728\u7535\u5b50\u5546\u52a1\u5e73\u53f0<\/h2>\n\n\n\n<p>\u80cc\u666f<\/p>\n\n\n\n<p>\u5047\u8bbe\u4f60\u6b63\u5728\u5f00\u53d1\u4e00\u4e2a\u7535\u5b50\u5546\u52a1\u5e73\u53f0\u7684\u540e\u7aef\u670d\u52a1\uff0c\u8be5\u670d\u52a1\u63d0\u4f9b\u4e86\u4e00\u4e2aAPI\u7aef\u70b9\uff0c\u5141\u8bb8\u5ba2\u6237\u63d0\u4ea4\u8ba2\u5355\u3002\u6bcf\u4e2a\u8ba2\u5355\u90fd\u6709\u591a\u4e2a\u5b57\u6bb5\uff0c\u5982\u4ea7\u54c1ID\u3001\u6570\u91cf\u3001\u652f\u4ed8\u65b9\u5f0f\u7b49\u3002\u4f60\u5e0c\u671b\u9a8c\u8bc1\u8fd9\u4e9b\u8f93\u5165\u53c2\u6570\u7684\u6709\u6548\u6027\u5e76\u8f6c\u6362\u4e3a\u5185\u90e8\u4f7f\u7528\u7684Python\u5bf9\u8c61\u3002<\/p>\n\n\n\n<p>\u5e38\u89c1\u6280\u672f\u5bf9\u6bd4<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u624b\u52a8\u9a8c\u8bc1<\/strong>\uff1a\u4f60\u53ef\u4ee5\u5728\u4ee3\u7801\u4e2d\u624b\u52a8\u68c0\u67e5\u6bcf\u4e2a\u5b57\u6bb5\uff0c\u4f46\u8fd9\u6837\u505a\u5f88\u5197\u957f\uff0c\u5bb9\u6613\u51fa\u9519\u3002<\/li>\n\n\n\n<li><strong>JSON Schema<\/strong>\uff1a\u63d0\u4f9b\u4e00\u79cd\u7ed3\u6784\u5316\u7684\u9a8c\u8bc1\u65b9\u6cd5\uff0c\u4f46\u9700\u8981\u989d\u5916\u7684\u5b9a\u4e49\u548c\u89e3\u6790\u6b65\u9aa4\u3002<\/li>\n\n\n\n<li><strong>Marshmallow<\/strong>\uff1a\u4e5f\u662f\u4e00\u79cd\u5e38\u7528\u4e8e\u6570\u636e\u9a8c\u8bc1\u7684\u5e93\uff0c\u4f46\u4e0ePydantic\u76f8\u6bd4\uff0c\u5b83\u66f4\u4fa7\u91cd\u4e8e\u5e8f\u5217\u5316\u548c\u53cd\u5e8f\u5217\u5316\uff0c\u800c\u4e0d\u662f\u7c7b\u578b\u5b89\u5168\u3002<\/li>\n<\/ul>\n\n\n\n<p>Pydantic \u7684\u5b9e\u9645\u5e94\u7528<\/p>\n\n\n\n<p>\u4f7f\u7528 Pydantic\uff0c\u4f60\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a&nbsp;<code>Order<\/code>\u6a21\u578b\u6765\u81ea\u52a8\u5b8c\u6210\u8fd9\u4e9b\u5de5\u4f5c\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from pydantic import BaseModel, Field\n\nclass Order(BaseModel):\n    product_id: int = Field(..., gt=0)\n    quantity: int = Field(..., gt=0, le=100)\n    payment_method: str = Field(..., regex=\"^(credit_card|paypal)$\")<\/code><\/pre>\n\n\n\n<p>\u529f\u80fd<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u7c7b\u578b\u68c0\u67e5<\/strong>:\u00a0<code>product_id<\/code>\u548c\u00a0<code>quantity<\/code>\u5fc5\u987b\u662f\u6574\u6570\u3002<\/li>\n\n\n\n<li><strong>\u8303\u56f4\u9a8c\u8bc1<\/strong>:\u00a0<code>product_id<\/code>\u5fc5\u987b\u5927\u4e8e0\uff0c<code>quantity<\/code>\u5fc5\u987b\u57281\u5230100\u4e4b\u95f4\u3002<\/li>\n\n\n\n<li><strong>\u6b63\u5219\u5339\u914d<\/strong>:\u00a0<code>payment_method<\/code>\u53ea\u80fd\u662f &#8220;credit_card&#8221; \u6216 &#8220;paypal&#8221;\u3002<\/li>\n<\/ol>\n\n\n\n<p>\u4f7f\u7528<\/p>\n\n\n\n<p>\u5f53\u5ba2\u6237\u901a\u8fc7API\u63d0\u4ea4\u4e00\u4e2a\u8ba2\u5355\u65f6\uff0c\u4f60\u53ea\u9700\u5c06\u8f93\u5165\u6570\u636e\u4f20\u9012\u7ed9\u8fd9\u4e2a&nbsp;<code>Order<\/code>\u6a21\u578b\u3002\u5982\u679c\u6570\u636e\u65e0\u6548\uff0cPydantic \u5c06\u81ea\u52a8\u629b\u51fa\u4e00\u4e2a\u8be6\u7ec6\u7684\u9519\u8bef\uff0c\u6307\u51fa\u54ea\u4e2a\u5b57\u6bb5\u65e0\u6548\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>order_data = {\n    \"product_id\": 1,\n    \"quantity\": 50,\n    \"payment_method\": \"credit_card\"\n}\n\ntry:\n    order = Order(**order_data)\nexcept ValidationError as e:\n    print(e.json())<\/code><\/pre>\n\n\n\n<p>\u8fd9\u79cd\u65b9\u5f0f\u4f7f\u5f97\u4ee3\u7801\u66f4\u7b80\u6d01\uff0c\u66f4\u6613\u4e8e\u7ef4\u62a4\uff0c\u540c\u65f6\u63d0\u4f9b\u4e86\u5f3a\u7c7b\u578b\u548c\u81ea\u52a8\u9a8c\u8bc1\u7684\u4f18\u70b9\u3002\u4e0e\u624b\u52a8\u9a8c\u8bc1\u6216\u4f7f\u7528\u5176\u4ed6\u5e93\u76f8\u6bd4\uff0cPydantic \u63d0\u4f9b\u4e86\u4e00\u4e2a\u66f4\u4e3a\u9ad8\u6548\u548c\u76f4\u89c2\u7684\u89e3\u51b3\u65b9\u6848\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h_652791602_3\">\u793a\u4f8b\uff1a\u7528\u6237\u6ce8\u518cAPI\u4e0ePydantic\u7684\u6570\u636e\u9a8c\u8bc1<\/h2>\n\n\n\n<p>\u4ee3\u7801\u8bbe\u7f6e<\/p>\n\n\n\n<p>\u5728\u8fd9\u4e2a\u793a\u4f8b\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528 FastAPI \u6784\u5efa\u4e00\u4e2a\u7b80\u5355\u7684\u7528\u6237\u6ce8\u518c API\u3002FastAPI \u4e0e Pydantic \u96c6\u6210\u975e\u5e38\u7d27\u5bc6\uff0c\u7528\u4e8e\u8bf7\u6c42\u548c\u54cd\u5e94\u6a21\u578b\u7684\u9a8c\u8bc1\u3002\u6211\u4eec\u5c06\u6bd4\u8f83\u4f7f\u7528 Pydantic \u548c\u624b\u52a8\u9a8c\u8bc1\u7684\u5dee\u5f02\u3002<\/p>\n\n\n\n<p>\u9996\u5148\uff0c\u6211\u4eec\u5bfc\u5165\u5fc5\u8981\u7684\u6a21\u5757\u5e76\u8bbe\u7f6e FastAPI \u5e94\u7528\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from fastapi import FastAPI, HTTPException\nfrom pydantic import BaseModel, EmailStr, Field\nfrom typing import Optional\n\napp = FastAPI()<\/code><\/pre>\n\n\n\n<p>Pydantic \u6570\u636e\u6a21\u578b<\/p>\n\n\n\n<p>\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u4f7f\u7528 Pydantic \u5b9a\u4e49\u4e00\u4e2a\u7528\u6237\u6ce8\u518c\u7684\u6570\u636e\u6a21\u578b\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class UserRegister(BaseModel):\n    username: str = Field(..., min_length=3, max_length=50)\n    email: EmailStr\n    password: str = Field(..., min_length=8)\n    age: Optional&#91;int] = Field(None, ge=18)<\/code><\/pre>\n\n\n\n<p>\u5728\u8fd9\u4e2a\u6a21\u578b\u4e2d\uff0c\u6211\u4eec\u5b9a\u4e49\u4e86\u5982\u4e0b\u5b57\u6bb5\u548c\u9a8c\u8bc1\u89c4\u5219\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>username<\/code>: \u5b57\u7b26\u4e32\u7c7b\u578b\uff0c\u957f\u5ea6\u5fc5\u987b\u57283\u523050\u5b57\u7b26\u4e4b\u95f4\u3002<\/li>\n\n\n\n<li><code>email<\/code>: \u5fc5\u987b\u662f\u6709\u6548\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002<\/li>\n\n\n\n<li><code>password<\/code>: \u5b57\u7b26\u4e32\u7c7b\u578b\uff0c\u81f3\u5c11\u5305\u542b8\u4e2a\u5b57\u7b26\u3002<\/li>\n\n\n\n<li><code>age<\/code>: \u6574\u6570\u7c7b\u578b\uff0c\u53ef\u9009\uff0c\u4f46\u5982\u679c\u63d0\u4f9b\u5fc5\u987b\u5927\u4e8e\u7b49\u4e8e18\u3002<\/li>\n<\/ul>\n\n\n\n<p>FastAPI \u8def\u7531\u4e0e\u9a8c\u8bc1<\/p>\n\n\n\n<p>\u4f7f\u7528 Pydantic \u6a21\u578b\uff0c\u6211\u4eec\u53ef\u4ee5\u5f88\u5bb9\u6613\u5730\u5728 FastAPI \u8def\u7531\u4e2d\u8fdb\u884c\u6570\u636e\u9a8c\u8bc1\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@app.post(\"\/register\/\")\ndef register(user: UserRegister):\n    return {\"username\": user.username, \"email\": user.email}<\/code><\/pre>\n\n\n\n<p>\u5bf9\u6bd4\uff1a\u624b\u52a8\u9a8c\u8bc1<\/p>\n\n\n\n<p>\u5982\u679c\u4e0d\u4f7f\u7528 Pydantic\uff0c\u6570\u636e\u9a8c\u8bc1\u4f1a\u53d8\u5f97\u590d\u6742\u548c\u5197\u957f\u3002\u4f8b\u5982\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@app.post(\"\/register_manual\/\")\ndef register_manual(username: str, email: str, password: str, age: Optional&#91;int] = None):\n    if len(username) &lt; 3 or len(username) &gt; 50:\n        raise HTTPException(status_code=400, detail=\"Invalid username length\")\n\n    <em># ...\u5176\u4ed6\u5b57\u6bb5\u9a8c\u8bc1<\/em>\n\n    return {\"username\": username, \"email\": email}<\/code><\/pre>\n\n\n\n<p>\u5728\u8fd9\u4e2a\u624b\u52a8\u9a8c\u8bc1\u7684\u793a\u4f8b\u4e2d\uff0c\u6211\u4eec\u9700\u8981\u4e3a\u6bcf\u4e2a\u5b57\u6bb5\u5199\u591a\u884c\u9a8c\u8bc1\u4ee3\u7801\uff0c\u8fd9\u663e\u7136\u4e0d\u5982\u4f7f\u7528 Pydantic \u6548\u7387\u9ad8\u3002<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>pydantic\u7684\u6838\u5fc3\u662f\u6a21\u578b\uff08Model\uff09<\/strong><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u9a8c\u8bc1\u6570\u636e<\/h4>\n\n\n\n<p>\u4e00\u65e6\u4f60\u5b9a\u4e49\u4e86\u6a21\u578b\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u9a8c\u8bc1\u6570\u636e\u3002<\/p>\n\n\n\n<p>\u5982\u679c\u8981\u4ece\u5b57\u5178\u5b9e\u4f8b\u5316 User \u5bf9\u8c61\uff0c\u53ef\u4ee5\u4f7f\u7528<code>\u5b57\u5178\u5bf9\u8c61\u89e3\u5305<\/code>\u8005<code>.model_validate()<\/code>\u3001<code>.model_validate_json()<\/code>\u7c7b\u65b9\u6cd5\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if __name__ == '__main__':\n\n    user_data = {\n        \"id\": 123,\n        \"name\": \"\u5c0f\u5364\u86cb\",\n        \"age\": 20,\n        \"email\": \"xiaoludan@example.com\",\n        'signup_ts': '2024-07-19 00:22',\n        'friends': &#91;\"\u516c\u4f17\u53f7\uff1a\u6d77\u54e5python\", '\u5c0f\u5929\u624d', b''],\n        'password': '123456',\n        'phone': '13800000000',\n        'sex': '\u7537'\n    }\n\n    try:\n        # user = User(**user_data)\n        user = User.model_validate(user_data)\n        print(f\"User id: {user.id}, User name: {user.name}, User email: {user.email}\")\n    except ValidationError as e:\n        print(f\"Validation error: {e.json()}\")\n<\/code><\/pre>\n\n\n\n<p>\u90fd\u7b26\u5408\u6a21\u578b\u5b9a\u4e49\u7684\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u4ee5\u50cf\u5f80\u5e38\u4e00\u6837\u8bbf\u95ee\u6a21\u578b\u7684\u5c5e\u6027\uff1a<\/p>\n\n\n\n<p>User id: 123, User name: \u5c0f\u5364\u86cb, User email: xiaoludan@example.com<br>1<br>\u5982\u679c\u6570\u636e\u4e0d\u7b26\u5408\u6a21\u578b\u7684\u5b9a\u4e49(\u4ee5\u4e0b\u6545\u610f\u4e0d\u4f20 id \u5b57\u6bb5)\uff0cPydantic \u5c06\u629b\u51fa\u4e00\u4e2a ValidationError\u3002<br><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u81ea\u5b9a\u4e49\u9a8c\u8bc1<\/h4>\n\n\n\n<p>\u9664\u4e86\u5185\u7f6e\u7684\u9a8c\u8bc1\u5668\uff0c\u8fd8\u53ef\u4ee5\u4e3a\u6a21\u578b\u5b9a\u4e49\u81ea\u5b9a\u4e49\u9a8c\u8bc1\u5668\u3002\u5047\u8bbe\u8981\u786e\u4fdd\u7528\u6237\u5e74\u9f84\u572818\u5c81\u4ee5\u4e0a\uff0c\u53ef\u4ee5\u4f7f\u7528<code>@field_validator<\/code>\u88c5\u9970\u5668\u521b\u5efa\u4e00\u4e2a\u81ea\u5b9a\u4e49\u9a8c\u8bc1\u5668\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># ! -*-conding: UTF-8 -*-\nfrom datetime import datetime\nfrom typing import List, Optional\nfrom pydantic import BaseModel, EmailStr, field_validator, ValidationError\n\n\ndef check_name(v: str) -> str:\n    \"\"\"Validator to be used throughout\"\"\"\n    if not v.startswith(\"\u5c0f\"):\n        raise ValueError(\"must be startswith \u5c0f\")\n    return v\n\n\nclass User(BaseModel):\n    id: int\n    name: str = \"\u5c0f\u5364\u86cb\"\n    age: int\n    email: EmailStr\n    signup_ts: Optional&#91;datetime] = None\n    friends: List&#91;str] = &#91;]\n\n    validate_fields = field_validator(\"name\")(check_name)\n'''\u4e0a\u9762\u8fd9\u884c\u4ee3\u7801\u662f\u4f7f\u7528field_validator\u88c5\u9970\u5668\u6765\u4e3aname\u5b57\u6bb5\u6dfb\u52a0\u4e00\u4e2a\u81ea\u5b9a\u4e49\u7684\u9a8c\u8bc1\u51fd\u6570check_name\u3002field_validator\u88c5\u9970\u5668\u5141\u8bb8\u4f60\u4e3a\u6a21\u578b\u7684\u5b57\u6bb5\u6307\u5b9a\u4e00\u4e2a\u6216\u591a\u4e2a\u9a8c\u8bc1\u51fd\u6570\uff0c\u8fd9\u4e9b\u51fd\u6570\u5c06\u5728\u6a21\u578b\u5b9e\u4f8b\u5316\u65f6\u81ea\u52a8\u8c03\u7528\uff0c\u4ee5\u786e\u4fdd\u5b57\u6bb5\u503c\u7b26\u5408\u7279\u5b9a\u7684\u6761\u4ef6\u3002\n\"name\"\uff1a\u6307\u5b9a\u4e86\u8981\u9a8c\u8bc1\u7684\u5b57\u6bb5\u540d\u3002\ncheck_name\uff1a\u662f\u4e00\u4e2a\u81ea\u5b9a\u4e49\u7684\u9a8c\u8bc1\u51fd\u6570\uff0c\u5b83\u63a5\u53d7\u4e00\u4e2a\u5b57\u7b26\u4e32\u53c2\u6570v\uff0c\u5e76\u68c0\u67e5\u8fd9\u4e2a\u5b57\u7b26\u4e32\u662f\u5426\u4ee5\"\u5c0f\"\u5f00\u5934\u3002\u5982\u679c\u4e0d\u662f\uff0c\u5b83\u5c06\u629b\u51fa\u4e00\u4e2aValueError\u3002\n\n\u4e0b\u9762\u7684@field_validator(\"age\")\u662f\u4e00\u4e2a\u88c5\u9970\u5668\uff0c\u7528\u4e8e\u4e3aage\u5b57\u6bb5\u6dfb\u52a0\u4e00\u4e2a\u81ea\u5b9a\u4e49\u7684\u9a8c\u8bc1\u51fd\u6570\u3002@field_validator\u88c5\u9970\u5668\u7684\u5de5\u4f5c\u65b9\u5f0f\u4e0efield_validator\u7c7b\u4f3c\uff0c\u4f46\u5b83\u662f\u4f5c\u4e3a\u4e00\u4e2a\u88c5\u9970\u5668\u76f4\u63a5\u5e94\u7528\u4e8e\u65b9\u6cd5\u4e0a\u7684\uff0c\u800c\u4e0d\u662f\u4f5c\u4e3a\u7c7b\u5c5e\u6027\u3002\n\"age\"\uff1a\u6307\u5b9a\u4e86\u8981\u9a8c\u8bc1\u7684\u5b57\u6bb5\u540d\u3002\ncheck_age\uff1a\u662f\u4e00\u4e2a\u7c7b\u65b9\u6cd5\uff0c\u5b83\u63a5\u53d7\u4e00\u4e2a\u53c2\u6570age\uff0c\u5e76\u68c0\u67e5\u8fd9\u4e2a\u503c\u662f\u5426\u5c0f\u4e8e18\u3002\u5982\u679c\u662f\uff0c\u5b83\u5c06\u629b\u51fa\u4e00\u4e2aValueError\u3002\n'''\n\n    @field_validator(\"age\")\n    @classmethod\n    def check_age(cls, age):\n        if age &lt; 18:\n            raise ValueError(\"\u7528\u6237\u5e74\u9f84\u5fc5\u987b\u5927\u4e8e18\u5c81\")\n        return age\n\n\u5f53\u5c1d\u8bd5\u521b\u5efa\u4e00\u4e2a\u53ea\u670912\u5c81\u7684\u5c0f\u670b\u53cb\u7528\u6237:\n\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>if __name__ == '__main__':\n    user_data = {\n        \"id\": 123,\n        \"name\": \"\u5c0f\u5364\u86cb\",\n        \"age\": 12,\n        \"email\": \"xiaoludan@example.com\",\n        'signup_ts': '2024-07-19 00:22',\n        'friends': &#91;\"\u516c\u4f17\u53f7\uff1a\u6d77\u54e5python\", '\u5c0f\u5929\u624d', b''],\n    }\n    try:\n        user = User(**user_data)\n    except ValidationError as e:\n        print(f\"Validation error: {e.json()}\")\n\n\u5c06\u5f97\u5230\u4e00\u4e2a\u9519\u8bef\uff1a\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>Validation error: &#91;{\"type\":\"value_error\",\"loc\":&#91;\"age\"],\"msg\":\"Value error, \u7528\u6237\u5e74\u9f84\u5fc5\u987b\u5927\u4e8e18\u5c81\",\"input\":12,\"ctx\":{\"error\":\"\u7528\u6237\u5e74\u9f84\u5fc5\u987b\u5927\u4e8e18\u5c81\"},\"url\":\"https:\/\/errors.pydantic.dev\/2.8\/v\/value_error\"}]\n\n\u6216\u8005\uff0c\u5f53name\u4e0d\u662f\u5c0f\u5f00\u5934\u7684\u8bdd\u4e5f\u4f1a\u62a5\u9519\n\n\u5982\u679c\u8981\u540c\u65f6\u52a8\u6001\u6821\u9a8c\u591a\u4e2a\u5b57\u6bb5\uff0c\u8fd8\u53ef\u4ee5\u4f7f\u7528model_validator\u88c5\u9970\u5668\u3002\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># ! -*-conding: UTF-8 -*-\n# @\u516c\u4f17\u53f7: \u6d77\u54e5python\nfrom datetime import datetime\nfrom typing import List, Optional\nfrom typing_extensions import Self  # \u5982\u679cpython\u7248\u672c\u4e0d\u4f4e\u4e8e3.11\uff0c\u5219\u53ef\u4ee5\u76f4\u63a5\u4ecetyping\u4e2d\u5bfc\u5165Self\nfrom pydantic import BaseModel, ValidationError, EmailStr, field_validator, model_validator\n\n\ndef check_name(v: str) -> str:\n    \"\"\"Validator to be used throughout\"\"\"\n    if not v.startswith(\"\u5c0f\"):\n        raise ValueError(\"must be startswith \u5c0f\")\n    return v\n\n\nclass User(BaseModel):\n    id: int\n    name: str = \"\u5c0f\u5364\u86cb\"\n    age: int\n    email: EmailStr\n    signup_ts: Optional&#91;datetime] = None\n    friends: List&#91;str] = &#91;]\n\n    validate_fields = field_validator(\"name\")(check_name)\n\n    @field_validator(\"age\")\n    @classmethod\n    def check_age(cls, age):\n        if age &lt; 18:\n            raise ValueError(\"\u7528\u6237\u5e74\u9f84\u5fc5\u987b\u5927\u4e8e18\u5c81\")\n        return age\n\n    @model_validator(mode=\"after\")\n    def check_age_and_name(self) -> Self:\n        if self.age &lt; 30 and self.name != \"\u5c0f\u5364\u86cb\":\n            raise ValueError(\"\u7528\u6237\u5e74\u9f84\u5fc5\u987b\u5c0f\u4e8e30\u5c81, \u4e14\u540d\u5b57\u5fc5\u987b\u4e3a\u5c0f\u5364\u86cb\")\n\n        return self\n\n\nif __name__ == '__main__':\n    user_data = {\n        \"id\": 123,\n        \"name\": \"\u5c0f\u5c0f\u5364\u86cb\",\n        \"age\": 20,\n        \"email\": \"xiaoludan@example.com\",\n        'signup_ts': '2024-07-19 00:22',\n        'friends': &#91;\"\u516c\u4f17\u53f7\uff1a\u6d77\u54e5python\", '\u5c0f\u5929\u624d', b''],\n    }\n    try:\n        user = User(**user_data)\n        print(user.model_dump())\n    except ValidationError as e:\n        print(f\"Validation error: {e.json()}\")\n\n\u6df1\u5165\u5b66\u4e60\u4ee5\u4e0b<\/code><\/pre>\n\n\n\n<p><a href=\"https:\/\/blog.csdn.net\/python_9k\/article\/details\/140711001\">https:\/\/blog.csdn.net\/python_9k\/article\/details\/140711001<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/blog.csdn.net\/weixin_43936332\/article\/details\/131627430\">https:\/\/blog.csdn.net\/weixin_43936332\/article\/details\/131627430<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5728\u5904\u7406\u6765\u81ea\u7cfb\u7edf\u5916\u90e8\u7684\u6570\u636e\uff0c\u5982API\u3001\u7ec8\u7aef\u7528\u6237\u8f93\u5165\u6216\u5176\u4ed6\u6765\u6e90\u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u7262\u8bb0\u5f00\u53d1\u4e2d\u7684\u4e00\u6761\u57fa\u672c\u539f\u5219\uff1a\u201c\u6c38\u8fdc\u4e0d\u8981\u76f8\u4fe1 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"class_list":["post-2116","post","type-post","status-publish","format-standard","hentry","category-10"],"_links":{"self":[{"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/posts\/2116","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/comments?post=2116"}],"version-history":[{"count":6,"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/posts\/2116\/revisions"}],"predecessor-version":[{"id":2122,"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/posts\/2116\/revisions\/2122"}],"wp:attachment":[{"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/media?parent=2116"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/categories?post=2116"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.xtaa.cn\/index.php\/wp-json\/wp\/v2\/tags?post=2116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}