{"id":49901,"date":"2023-08-02T10:44:23","date_gmt":"2023-11-27T09:43:44","guid":{"rendered":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/"},"modified":"2024-04-30T16:37:07","modified_gmt":"2024-04-30T08:37:07","slug":"%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api","status":"publish","type":"post","link":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/","title":{"rendered":"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API"},"content":{"rendered":"<h2>\u9996\u5148<\/h2>\n<p>\u6700\u8fd1\u6211\u5728\u5b66\u4e60\u4f7f\u7528Docker\u548cDjango REST\u6846\u67b6\uff0c\u5c1d\u8bd5\u521b\u5efa\u4e00\u4e2aTodo\u5e94\u7528\u7684API\u3002\u6211\u4f1a\u5728\u8fd9\u91cc\u8bb0\u5f55\u521d\u5b66\u8005\u7684\u594b\u6597\u8fc7\u7a0b\u3002\uff08\u6e90\u4ee3\u7801\u5728\u8fd9\u91cc\uff09<\/p>\n<h2>\u5b9e\u73b0\u76ee\u6807<\/h2>\n<ul class=\"post-ul\">\n<li style=\"list-style-type: none;\">\n<ul class=\"post-ul\">Docker \u3092\u7528\u3044\u305f\u958b\u767a\u74b0\u5883\u69cb\u7bc9<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<ul class=\"post-ul\">Django REST framework \u3092\u4f7f\u3063\u305f\u7c21\u6613\u306a API \u4f5c\u6210<\/ul>\n<h2>\u73af\u5883<\/h2>\n<pre class=\"post-pre\"><code>macOS Catalina 10.15.2\r\ndocker desktop community 2.3.0.3\r\ndocker version Client: 19.03.8\r\ndocker version Server: 19.03.8\r\n<\/code><\/pre>\n<h2>\u8f93\u5165<\/h2>\n<h3>Django REST\u6846\u67b6\u7684\u6982\u8ff0<\/h3>\n<p>Django REST Framework\u662f\u4e00\u4e2a\u652f\u6301\u4f7f\u7528Django\u5f00\u53d1Web API\u7684\u6846\u67b6\uff0c\u800cDjango\u5219\u662f\u7528\u4e8e\u5728Python\u4e2d\u521b\u5efaWeb\u5e94\u7528\u7a0b\u5e8f\u7684\u6846\u67b6\u3002\u901a\u8fc7\u4f7f\u7528Django REST Framework\uff0c\u60a8\u53ef\u4ee5\u8f7b\u677e\u6784\u5efa\u7b26\u5408RESTful\u8bbe\u8ba1\u7684API\u540e\u7aef\u3002\u6709\u5173RESTful API\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u8003\u6b64\u5904\u3002<\/p>\n<h3>Docker \u7684\u6982\u8ff0<\/h3>\n<p>Docker\u662f\u4e00\u4e2a\u7b80\u5316\u5bb9\u5668\u865a\u62df\u5316\u6280\u672f\u64cd\u4f5c\u7684\u8f6f\u4ef6\u3002<br \/>\n\u4e0e\u4f20\u7edf\u7684\u865a\u62df\u73af\u5883\u6784\u5efa\u76f8\u6bd4\uff0c\u5b83\u53ef\u4ee5\u5229\u7528\u6700\u5c11\u7684\u786c\u4ef6\u8d44\u6e90\u6765\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\u66f4\u5feb\uff0c\u63d0\u4f9b\u5df2\u7ecf\u6784\u5efa\u597d\u7684\u5305\u542b\u64cd\u4f5c\u7cfb\u7edf\u548c\u5e94\u7528\u7a0b\u5e8f\u7b49\u73af\u5883\u7684\u5bb9\u5668\u6620\u50cf\uff0c\u4f7f\u5f97\u6784\u5efa\u65b0\u5e94\u7528\u7a0b\u5e8f\u66f4\u52a0\u7b80\u5355\u3002\u6211\u53d1\u73b0\u8fd9\u7bc7\u5173\u4e8eDocker\u7684\u6587\u7ae0\u975e\u5e38\u6709\u53c2\u8003\u4ef7\u503c\uff0c\u6211\u591a\u6b21\u9605\u8bfb\u4e86\u5b83\u3002<\/p>\n<h2>\u5b89\u88c5Docker<\/h2>\n<p>\u4eceDocker\u5b98\u7f51\u6ce8\u518cDocker\u8d26\u6237\u5e76\u5b89\u88c5Docker\u3002<br \/>\n\u8fdb\u5165\u5b89\u88c5\u9875\u9762\uff0c\u53ef\u80fd\u4f1a\u770b\u5230&#8221;Get Stable&#8221;\u548c&#8221;Get Edge&#8221;\u9009\u9879\u3002<br \/>\n\u597d\u50cf\u8fd9\u662f\u66f4\u65b0\u9891\u7387\u7684\u4e0d\u540c\uff0c&#8221;Stable&#8221;\u6bcf\u4e09\u4e2a\u6708\u66f4\u65b0\u4e00\u6b21\uff0c&#8221;Edge&#8221;\u6bcf\u6708\u66f4\u65b0\u4e00\u6b21\u3002<br \/>\n\u8fd9\u4e2a\u9009\u9879\u4e4b\u540e\u53ef\u4ee5\u968f\u65f6\u66f4\u6539\uff0c\u6240\u4ee5\u5148\u65e0\u6240\u8c13\u9009\u62e9\u54ea\u4e2a\u3002<\/p>\n<p>\u8bf7\u53c2\u9605\u6b64\u6587\u7ae0\u4ee5\u83b7\u53d6\u5173\u4e8e\u8d26\u6237\u521b\u5efa\u548c\u5b89\u88c5\u7684\u8be6\u7ec6\u6b65\u9aa4\u3002<\/p>\n<h2>\u8ba9\u6211\u4eec\u642d\u5efa\u73af\u5883\u3002<\/h2>\n<h3>\u5728GitHub\u4e0a\u521b\u5efa\u4ee3\u7801\u5e93\u3002<\/h3>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/16-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-20 7.43.38.png\" \/><\/div>\n<h3>\u5c06\u514b\u9686\u6587\u4ef6\u5230\u672c\u5730\u7535\u8111\u3002<\/h3>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/18-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-20 7.58.28.png\" \/><\/div>\n<p>\u5c06URL\u590d\u5236\u5230\u7ec8\u7aef\uff0c\u7136\u540e\u8f93\u5165git\u547d\u4ee4\u3002<\/p>\n<pre class=\"post-pre\"><code>$ git clone https:\/\/github.com\/Yi-Gaoqiao\/todo-api.git\r\n<\/code><\/pre>\n<p>\u5728\u514b\u9686\u7684\u4ee3\u7801\u5e93\u4e2d\u5207\u6362\u5230\u6240\u9700\u76ee\u5f55\uff0c\u5e76\u68c0\u67e5\u5176\u5185\u5bb9\u540e\u6253\u5f00\u7f16\u8f91\u5668\u3002<\/p>\n<pre class=\"post-pre\"><code>$ cd todo-api\/         # \u4f5c\u696d\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306b\u79fb\u52d5\r\n$ ls                   # \u4e2d\u8eab\u3092\u78ba\u8a8d\r\nLICENSE   README.md\r\n$ code .               # vscode\u8d77\u52d5\r\n<\/code><\/pre>\n<h3>\u521b\u5efaDockerfile<\/h3>\n<p>\u6211\u5011\u5c07\u5275\u5efa\u4e00\u500b\u65b0\u7684Dockerfile\uff08\u7528\u65bc\u69cb\u5efaDocker\u6620\u50cf\uff09\uff0c\u4e26\u6309\u7167\u4ee5\u4e0b\u65b9\u5f0f\u9032\u884c\u63cf\u8ff0\uff1a<br \/>\n\/todo-api\/Dockerfile<\/p>\n<pre class=\"post-pre\"><code>FROM python:3.7-alpine                       # \u30d9\u30fc\u30b9\u3068\u3059\u308bDocker\u30a4\u30e1\u30fc\u30b8\u3092\u6307\u5b9a\r\nLABEL architecture=\"Your Name\"               # \u69cb\u7bc9\u62c5\u5f53\u8005\u3092\u30e9\u30d9\u30eb\u4ed8\u3051\r\n\r\nENV PYTHONUNBUFFERD 1                        # \u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u30ed\u30b0\u3092\u898b\u308c\u308b\u3088\u3046\u306b\u74b0\u5883\u5909\u6570\u3092\u6307\u5b9a\r\n\r\nCOPY .\/requirements.txt \/requirements.txt    # \u30ed\u30fc\u30ab\u30eb\u306erequirements.txt\u3092\u30b3\u30f3\u30c6\u30ca\u306b\u30b3\u30d4\u30fc\r\nRUN pip install -r \/requirements.txt         # requirements.txt\u306b\u5f93\u3063\u3066\u30d1\u30c3\u30b1\u30fc\u30b8\u3092\u4e00\u62ec\u3067\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\r\n\r\nRUN mkdir \/django-api                        # Django\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u7f6e\u304f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u30b3\u30f3\u30c6\u30ca\u4e0a\u306b\u4f5c\u6210\r\nWORKDIR \/django-api                          # \u30b3\u30f3\u30c6\u30ca\u4e0a\u306e\u4f5c\u696d\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u5909\u66f4\r\nCOPY .\/django-api \/django-api                # \u30ed\u30fc\u30ab\u30eb\u306edjango-api\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u30b3\u30f3\u30c6\u30ca\u306b\u30b3\u30d4\u30fc\r\n\r\nRUN adduser -D user                          # \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3059\u308b\u305f\u3081\u306e\u30e6\u30fc\u30b6\u3092\u4f5c\u6210\u3059\u308b\r\nUSER user                                    # \u30e6\u30fc\u30b6\u3092root\u304b\u3089\u5909\u66f4\r\n<\/code><\/pre>\n<p>\u4e3a\u4e86\u4e0d\u5fd8\u8bb0\u8fd9\u4e00\u70b9\uff0c\u6211\u4eec\u4f1a\u5728\u672c\u5730\u521b\u5efa\u4e00\u4e2a\u540d\u4e3adjango-api\u7684\u76ee\u5f55\u3002<\/p>\n<h3>\u521b\u5efa requirements.txt<\/h3>\n<p>\u8bf7\u5728\u8fd9\u91cc\u5217\u51fa\u6240\u9700\u7684\u5305\u548c\u7248\u672c\uff0c\u5e76\u4e00\u6b21\u6027\u5b89\u88c5\u5b83\u4eec\u3002<br \/>\n\u672c\u6b21\u6240\u9700\u7684\u5305\u662f Django \u548c djangorestframework\u3002\u53ef\u4ee5\u5728 PyPI \u4e0a\u641c\u7d22\u5404\u4e2a\u5305\u7684\u7248\u672c\u3002<br \/>\n\u6587\u4ef6\u7684\u5185\u5bb9\u5982\u4e0b\u6240\u793a\u3002<\/p>\n<p>\/todo-api\/requirements.txt \u7684\u8981\u6c42\u6587\u4ef6<\/p>\n<pre class=\"post-pre\"><code>Django&gt;=3.0.7,&lt;3.1.0\r\ndjangorestframework&gt;=3.11.0,&lt;3.12.0\r\n<\/code><\/pre>\n<h3>\u521b\u5efa docker-compose.yml \u6587\u4ef6<\/h3>\n<p>docker-compose.yml \u662f\u4e00\u500b\u8a18\u9304\u61c9\u7528\u7a0b\u5f0f\u57f7\u884c\u6240\u9700\u8655\u7406\u7684\u6587\u4ef6\u3002\u6b64\u5916\uff0c\u5b83\u662f\u4e00\u500b\u975e\u5e38\u65b9\u4fbf\u7684\u5de5\u5177\uff0c\u53ef\u4ee5\u8f15\u9b06\u5efa\u7acb\u591a\u500b\u5bb9\u5668\u7684\u61c9\u7528\u7a0b\u5f0f Docker \u6620\u50cf\uff0c\u4e26\u555f\u52d5\u548c\u505c\u6b62\u6bcf\u500b\u5bb9\u5668\u3002<br \/>\n\u9019\u6b21\u6211\u5011\u53ea\u60f3\u555f\u52d5\u4e00\u500b\u540d\u70ba app \u7684\u5bb9\u5668\u3002<\/p>\n<p>\/todo-api\/docker-compose.yml \u53ef\u4ee5\u88ab\u91cd\u8ff0\u4e3a\uff1a\/todo-api\/docker-compose.yml \u6587\u4ef6<\/p>\n<pre class=\"post-pre\"><code>version: \"3\"\r\n\r\nservices:\r\n  app:\r\n    build:\r\n      context: .\r\n    ports:\r\n      - \"8000:8000\"\r\n    volumes:\r\n      - .\/django-api:\/django-api\r\n    command: &gt;\r\n      sh -c \"python manage.py migrate &amp;&amp;\r\n             python manage.py runserver 0.0.0.0:8000\"\r\n<\/code><\/pre>\n<p>\u4ee5\u4e0b\u662f\u6bcf\u4e2a\u547d\u4ee4\u7684\u8bf4\u660e\u3002\u5982\u679c\u60f3\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u53c2\u9605\u8fd9\u7bc7\u6587\u7ae0\u3002<\/p>\n<p>services<\/p>\n<p>\u3053\u306e\u4e0b\u306b\u30b3\u30f3\u30c6\u30ca\u3092\u5b9a\u7fa9\u3002<\/p>\n<p>app<\/p>\n<p>\u30b3\u30f3\u30c6\u30ca\u306e\u540d\u524d\u3092\u6307\u5b9a\u3002<\/p>\n<p>build<\/p>\n<p>Dockerfile \u304c\u7f6e\u3044\u3066\u3042\u308b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30d1\u30b9\u3092\u8a18\u8ff0\u3002<br \/>\n\u914d\u5e03\u3055\u308c\u3066\u3044\u308b\u30a4\u30e1\u30fc\u30b8\uff08\u516c\u5f0f\u30a4\u30e1\u30fc\u30b8\u306a\u3069\uff09\u3092\u53d6\u5f97\u3059\u308b\u5834\u5408\u306f\u6307\u5b9a\u4e0d\u8981\u3002<\/p>\n<p>ports<\/p>\n<p>\u30dd\u30fc\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u3092\u6307\u5b9a\u3002&#8221;\u30db\u30b9\u30c8\u5074\uff1a\u30b3\u30f3\u30c6\u30ca\u5074&#8221;\u3002<\/p>\n<p>volumes<\/p>\n<p>\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30de\u30a6\u30f3\u30c8\u3002<br \/>\n\u30db\u30b9\u30c8\u5074\u304b\u3089\u30d5\u30a1\u30a4\u30eb\u3092\u914d\u7f6e\u3057\u305f\u308a\u7de8\u96c6\u3057\u305f\u308a\u3067\u304d\u308b\u3088\u3046\u30de\u30a6\u30f3\u30c8\u3059\u308b\u3002<\/p>\n<p>command<\/p>\n<p>\u30b3\u30f3\u30c6\u30ca\u8d77\u52d5\u6642\u306b\u5b9f\u884c\u3055\u308c\u308b\u30b3\u30de\u30f3\u30c9\u3002\u30b5\u30fc\u30d0\u30fc\u8d77\u52d5\u6642\u306b\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3059\u308b\u3088\u3046\u8a18\u8ff0\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<h3>\u4f7f\u7528 Dockerfile \u6784\u5efa Docker \u955c\u50cf\u3002<\/h3>\n<p>\u5728\u7ec8\u7aef\u4e2d\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\u3002<\/p>\n<pre class=\"post-pre\"><code>$ docker-compose build\r\nBuilding app\r\n...\r\nSuccessfully built f624466b62a4\r\nSuccessfully tagged todo-api_app:latest\r\n<\/code><\/pre>\n<p>\u5982\u679c\u547d\u4ee4\u6210\u529f\u6267\u884c\u540e\uff0c\u51fa\u73b0&#8221;Successfully tagged&#8230;&#8221;\u7684\u8bdd\uff0c\u90a3\u5c31\u5b8c\u6210\u4e86\u3002<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u4e0b\u4e00\u6761\u547d\u4ee4\u6765\u786e\u8ba4\u521b\u5efa\u7684\u955c\u50cf\u3002<\/p>\n<pre class=\"post-pre\"><code>$ docker images\r\nREPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE\r\ntodo-api_app                     latest              840de00a35b5        6 seconds ago       116MB\r\n<\/code><\/pre>\n<p>\u5230\u76ee\u524d\u4e3a\u6b62\u770b\u8d77\u6765\u6ca1\u6709\u95ee\u9898\u3002<\/p>\n<h2>\u521b\u5efaDjango\u9879\u76ee<\/h2>\n<p>\u8bf7\u5728\u7ec8\u7aef\u4e2d\u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u3002<br \/>\n\u6267\u884c\u547d\u4ee4\u540e\uff0c\u8bf7\u786e\u8ba4\u5728\u5148\u524d\u7684 django-api \u76ee\u5f55\u4e2d\u662f\u5426\u521b\u5efa\u4e86 todo_project\u3002<\/p>\n<pre class=\"post-pre\"><code>$ docker-compose run --rm app sh -c \"django-admin.py startproject todo_project .\"\r\n<\/code><\/pre>\n<p>&#8211;rm<\/p>\n<p>\u30b3\u30f3\u30c6\u30ca\u3092\u8d77\u52d5\u3057\u305f\u308a\u30a4\u30e1\u30fc\u30b8\u3092 build \u3057\u305f\u308a\u3057\u3066\u3044\u308b\u3068\u3001\u3069\u3093\u3069\u3093\u4f7f\u3063\u3066\u3044\u306a\u3044\u30b3\u30f3\u30c6\u30ca\u3084\u30a4\u30e1\u30fc\u30b8\u306a\u3069\u304c\u6e9c\u307e\u3063\u3066\u3044\u304d\u3001\u30c7\u30a3\u30b9\u30af\u5bb9\u91cf\u3092\u5727\u8feb\u3057\u3066\u3057\u307e\u3044\u307e\u3059\u3002\u305d\u308c\u3092\u9632\u3050\u305f\u3081\u306b\u3001\u30b3\u30de\u30f3\u30c9\u5b9f\u884c\u6642\u306b\u30b3\u30f3\u30c6\u30ca\u3092\u524a\u9664\u3057\u3066\u3057\u307e\u3044\u307e\u3059\u3002<\/p>\n<p>sh -c &#8220;&#8221;<\/p>\n<p>&#8220;&#8221;\u5185\u306b\u5b9f\u884c\u3059\u308b\u30b7\u30a7\u30eb\u30b9\u30af\u30ea\u30d7\u30c8\u3092\u8a18\u8ff0\u3057\u307e\u3059\u3002\u3053\u306e\u30b3\u30de\u30f3\u30c9\u306f\u5fc5\u9808\u3067\u306f\u306a\u3044\u307f\u305f\u3044\u3067\u3059\u304c\u3001\u500b\u4eba\u7684\u306b\u3069\u3053\u304b\u3089\u3069\u3053\u307e\u3067\u304c docker-compose \u306e\u30b3\u30de\u30f3\u30c9\u304b\u660e\u78ba\u306b\u3057\u305f\u3044\u306e\u3067\u4f7f\u3046\u3088\u3046\u306b\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<h2>\u521b\u5efaDjango\u5e94\u7528\u7a0b\u5e8f<\/h2>\n<p>\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\uff0c\u8bf7\u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u3002\u5e94\u7528\u7a0b\u5e8f\u540d\u79f0\u53ef\u4ee5\u6839\u636e\u60a8\u7684\u559c\u597d\u81ea\u7531\u8bbe\u5b9a\uff08\u6211\u5c06\u4f7f\u7528 core \u4f5c\u4e3a\u793a\u4f8b\uff09\u3002<\/p>\n<pre class=\"post-pre\"><code>$ docker-compose run --rm app sh -c \"python manage.py startapp core\"\r\n<\/code><\/pre>\n<h3>\u521b\u5efa\u81ea\u5b9a\u4e49\u7528\u6237\u6a21\u578b<\/h3>\n<p>\u5728 Django \u7684\u6807\u51c6 User \u6a21\u578b\u4e2d\uff0c\u7528\u6237\u8ba4\u8bc1\u65f6\u4f7f\u7528\u7684\u662f\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002<br \/>\n\u5bf9\u4e8e\u5927\u5bb6\u8ba4\u4e3a\u5728\u4e00\u822c\u7528\u6237\u6ce8\u518c\u65f6\u5e94\u8be5\u4f7f\u7528\u7535\u5b50\u90ae\u4ef6\u800c\u4e0d\u662f\u7528\u6237\u540d\u7684\u58f0\u97f3\uff0c\u6211\u4eec\u7279\u522b\u5b9a\u5236\u4e86 User \u6a21\u578b\u3002<br \/>\n\u62b1\u6b49\uff0c\u8fd9\u662f\u4e2a\u8c0e\u8a00\u3002\u4ee5\u4e0b\u662f\u6765\u81ea Django \u5b98\u65b9\u6587\u6863\u7684\u5185\u5bb9\u3002<\/p>\n<blockquote><p>\u5728\u5f00\u59cb\u4e00\u4e2a\u65b0\u9879\u76ee\u65f6\uff0c\u5373\u4f7f\u9ed8\u8ba4\u7684\u7528\u6237\u6a21\u578b\u5df2\u7ecf\u8db3\u591f\uff0c\u6211\u4eec\u5f3a\u70c8\u5efa\u8bae\u521b\u5efa\u4e00\u4e2a\u81ea\u5b9a\u4e49\u7528\u6237\u6a21\u578b\u3002\u8fd9\u4e2a\u6a21\u578b\u548c\u9ed8\u8ba4\u7528\u6237\u6a21\u578b\u4e00\u6837\u5de5\u4f5c\uff0c\u4f46\u53ef\u4ee5\u6839\u636e\u9700\u8981\u8fdb\u884c\u672a\u6765\u7684\u5b9a\u5236\u3002<\/p><\/blockquote>\n<p>\u56e0\u6b64\uff0c\u6211\u4f1a\u4ee5\u4ee5\u4e0b\u65b9\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002<\/p>\n<p>\/django-api\/core\/models.py \uff1a<br \/>\n\/ Django-api \/\u6838\u5fc3\/\u6a21\u578b.py<\/p>\n<pre class=\"post-pre\"><code>from django.db import models\r\nfrom django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin\r\nfrom django.conf import settings    # \u3042\u3068\u3067\u4f7f\u3044\u307e\u3059\u3002\r\n\r\nclass UserManager(BaseUserManager):\r\n\r\n    def create_user(self, email, password=None, **extra_fields):\r\n        \"\"\"Creates and saves a new user\"\"\"\r\n        if not email:\r\n            raise ValueError('User must have an email address')\r\n\r\n        email = self.normalize_email(email)\r\n        user = self.model(email=email, **extra_fields)\r\n        user.set_password(password)\r\n        user.save(using=self._db)\r\n\r\n        return user\r\n\r\n    def create_superuser(self, email, password):\r\n        \"\"\"Creates and saves a new superuser\"\"\"\r\n        user = self.create_user(email, password)\r\n        user.is_staff = True\r\n        user.is_superuser = True\r\n        user.save(using=self._db)\r\n\r\n        return user\r\n\r\n\r\nclass User(AbstractBaseUser, PermissionsMixin):\r\n    \"\"\"Custom user model that supports using email instead of username\"\"\"\r\n    email = models.EmailField(max_length=255, unique=True)\r\n    name = models.CharField(max_length=255)\r\n    is_active = models.BooleanField(default=True)\r\n    is_staff = models.BooleanField(default=False)\r\n\r\n    objects = UserManager()\r\n\r\n    USERNAME_FIELD = 'email'    # \u30c7\u30d5\u30a9\u30eb\u30c8\u306f\u540d\u524d\u5165\u529b\u3001\u4eca\u56de\u306f\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u306b\u30ab\u30b9\u30bf\u30e0\r\n<\/code><\/pre>\n<p>AbstractBaseUser<\/p>\n<p>\u6700\u4f4e\u9650\u306e\u30d5\u30a3\u30fc\u30eb\u30c9\u53ca\u3073\u6a5f\u80fd\u4ee5\u5916\u306f\u6301\u3061\u5408\u308f\u305b\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u52d5\u4f5c\u3092\u67d4\u8edf\u306b\u5b9a\u7fa9\u3057\u305f\u3044\u969b\u306b\u5229\u7528\u3002<br \/>\n\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u95a2\u9023\u306e\u6a5f\u80fd\u3092\u6301\u3061\u5408\u308f\u305b\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u306e\u6a5f\u80fd\u3092\u5229\u7528\u3057\u305f\u3044\u5834\u5408\u306f\u3001PermissionMixin \u3092\u540c\u6642\u306b\u7d99\u627f\u3057\u3066\u304a\u304f\u5fc5\u8981\u304c\u3042\u308b\u3002<\/p>\n<p>BaseUserManager<\/p>\n<p>\u30de\u30cd\u30fc\u30b8\u30e3\u30fc\u3092\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3059\u308b\u969b\u306b\u7d99\u627f\u3002<br \/>\n\u30de\u30cd\u30fc\u30b8\u30e3\u30fc\u306b\u95a2\u3057\u3066\u306f\u3053\u3061\u3089\u3092\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\u3002<\/p>\n<h3>\u6dfb\u52a0\u5e94\u7528\u7a0b\u5e8f\u548c\u58f0\u660e\u4f7f\u7528\u81ea\u5b9a\u4e49\u7528\u6237\u6a21\u578b\u3002<\/h3>\n<p>\/django-api\/todo-project\/settings.py \u53ef\u4ee5\u505a\u5982\u4e0b\u7684\u4e2d\u6587\u7ffb\u8bd1\uff1a<\/p>\n<pre class=\"post-pre\"><code>INSTALLED_APPS = [\r\n    'django.contrib.admin',\r\n    'django.contrib.auth',\r\n    'django.contrib.contenttypes',\r\n    'django.contrib.sessions',\r\n    'django.contrib.messages',\r\n    'django.contrib.staticfiles',\r\n    'core',  # \u8ffd\u52a0\r\n]\r\n\r\n~~~~\r\n \u7565\r\n~~~~\r\n\r\nSTATIC_URL = '\/static\/'\r\n\r\nAUTH_USER_MODEL = 'core.User'    # \u30d5\u30a1\u30a4\u30eb\u6700\u4e0b\u90e8\u306b\u8a18\u8ff0\r\n<\/code><\/pre>\n<p>\u6ce8\u610f\u4e8b\u9879\uff1a\u5728\u8fdb\u884c\u7b2c\u4e00\u6b21\u8fc1\u79fb\uff08init(0001)\uff09\u4e4b\u524d\uff0c\u52a1\u5fc5\u5148\u521b\u5efa\u5e76\u6ce8\u518c\u81ea\u5b9a\u4e49\u7528\u6237\u6a21\u578b\uff0c\u4ee5\u514d\u540e\u7eed\u51fa\u73b0\u4e0d\u4fbf\u4e4b\u5904\uff0c\u8bf7\u6ce8\u610f\u3002<\/p>\n<h3>\u8fc1\u79fb<\/h3>\n<pre class=\"post-pre\"><code>$ docker-compose run --rm app sh -c \"python manage.py makemigrations core\"\r\nMigrations for 'core':\r\n  core\/migrations\/0001_initial.py\r\n    - Create model User\r\n<\/code><\/pre>\n<h2>\u542f\u52a8\u7b2c\u4e00\u4e2a\u5bb9\u5668<\/h2>\n<p>\u6765\u5427\uff0c\u5404\u4f4d\uff0c\u5927\u5bb6\u671f\u5f85\u5df2\u4e45\u3002\u73b0\u5728\u662f\u5bb9\u5668\u542f\u52a8\u7684\u65f6\u523b\u5230\u4e86\u3002<\/p>\n<pre class=\"post-pre\"><code>$ docker-compose up\r\n...\r\napp_1  | Watching for file changes with StatReloade\r\n<\/code><\/pre>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/66-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-22 7.10.16.png\" \/><\/div>\n<h2>\u521b\u5efa\u8d85\u7ea7\u7528\u6237\u3002<\/h2>\n<pre class=\"post-pre\"><code>docker-compose run --rm app sh -c \"python manage.py createsuperuser\"\r\nEmail: superuser@dummy.co.jp\r\nPassword: \r\nPassword (again): \r\nSuperuser created successfully.\r\n<\/code><\/pre>\n<p>\u8f93\u5165\u4efb\u610f\u7684\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\uff08\u5bc6\u7801\u4e0d\u4f1a\u663e\u793a\u5728\u5c4f\u5e55\u4e0a\uff09\u3002<\/p>\n<h3>\u5728\u7ba1\u7406\u754c\u9762\u4e0a\u6ce8\u518c\u6a21\u578b\u3002<\/h3>\n<p>\u4e3a\u4e86\u5728\u7ba1\u7406\u754c\u9762\u4e0a\u80fd\u591f\u67e5\u770b\u5148\u524d\u521b\u5efa\u7684User\u6a21\u578b\uff0c\u6211\u4eec\u5c06\u5728admin.py\u4e2d\u8fdb\u884c\u66f4\u6539\u3002<br \/>\n\u7531\u4e8e\u6211\u4eec\u5bf9User\u6a21\u578b\u8fdb\u884c\u4e86\u81ea\u5b9a\u4e49\uff0c\u6240\u4ee5\u6211\u4eec\u4e5f\u9700\u8981\u5bf9\u8981\u663e\u793a\u5728\u7ba1\u7406\u754c\u9762\u4e0a\u7684\u9879\u76ee\u8fdb\u884c\u81ea\u5b9a\u4e49\u3002<\/p>\n<p>\/django-api\/core\/admin.py \u7684\u539f\u751f\u4e2d\u6587\u89e3\u91ca\uff1a<br \/>\n\/django-api\/core\/admin.py \u7684\u4e2d\u6587\u89e3\u91ca<\/p>\n<pre class=\"post-pre\"><code>from django.contrib import admin\r\nfrom django.contrib.auth.admin import UserAdmin as BaseUserAdmin\r\nfrom django.utils.translation import gettext as _\r\n\r\nfrom core import models\r\n\r\n\r\nclass UserAdmin(BaseUserAdmin):\r\n    ordering = ['id']\r\n    list_display = ['email', 'name']\r\n    fieldsets = (\r\n        (None, {'fields': ('email', 'password')}),\r\n        (_('Personal Info'), {'fields': ('name',)}),\r\n        (\r\n            _('Permissions'),\r\n             {'fields': ('is_active', 'is_staff', 'is_superuser')}\r\n        ),\r\n        (_('Important dates'), {'fields': ('last_login',)})\r\n    )\r\n\r\nadmin.site.register(models.User, UserAdmin)\r\n<\/code><\/pre>\n<p>\u7528\u6237\u6309\u7167 ID \u7684\u987a\u5e8f\u6392\u5217\uff0c\u5e76\u663e\u793a\u7535\u5b50\u90ae\u4ef6\u548c\u59d3\u540d\u3002\u53e6\u5916\uff0c\u5728 fieldsets \u4e2d\u6307\u5b9a\u4e86\u6bcf\u4e2a\u7528\u6237\u7684\u8be6\u7ec6\u4fe1\u606f\u9879\u3002<\/p>\n<p>BaseUserAdmin<\/p>\n<p>\u30c7\u30d5\u30a9\u30eb\u30c8\u306e UserAdmin \u3092 BaseUserAdmin \u3068\u3057\u3066\u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u3001\u305d\u308c\u3092\u7d99\u627f\u3059\u308b\u3053\u3068\u3067\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3057\u307e\u3059\u3002<\/p>\n<p>gettext as _<\/p>\n<p>gettext \u306f\u591a\u8a00\u8a9e\u5bfe\u5fdc\u306e\u305f\u3081\u306b\u5229\u7528\u3055\u308c\u307e\u3059\u3002\u6163\u7fd2\u7684\u306b as _ \u3068\u3057\u3066\u30a4\u30f3\u30dd\u30fc\u30c8\u3059\u308b\u307f\u305f\u3044\u3067\u3059\u3002\u4eca\u56de\u3001\u8a00\u8a9e\u8a2d\u5b9a\u306b\u95a2\u3057\u3066\u306f\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u82f1\u8a9e\u306e\u307e\u307e\u9032\u3081\u308b\u306e\u3067\u3001\u7ffb\u8a33\u306b\u95a2\u3057\u3066\u6c17\u306b\u306a\u308b\u65b9\u306f\u3053\u3061\u3089\u306e\u8a18\u4e8b\u3092\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\u3002<\/p>\n<h3>\u7528\u6d4f\u89c8\u5668\u786e\u8ba4<\/h3>\n<p>\u7531\u65bc\u50c5\u67e5\u770b\u4ee3\u78bc\u53ef\u80fd\u4e0d\u5bb9\u6613\u5f62\u6210\u5177\u9ad4\u7684\u5370\u8c61\uff0c\u6240\u4ee5\u8b93\u6211\u5011\u5be6\u969b\u4e0a\u524d\u5f80\u7ba1\u7406\u4ecb\u9762\u770b\u770b\u5b83\u662f\u5982\u4f55\u986f\u793a\u7684\u3002<br \/>\n\u4f7f\u7528docker-compose up\u547d\u4ee4\u555f\u52d5\u5bb9\u5668\uff0c\u7136\u5f8c\u8f49\u5230http:\/\/127.0.0.1:8000\/admin\/\uff0c\u78ba\u8a8d\u4e4b\u524d\u5275\u5efa\u7684\u8d85\u7d1a\u7528\u6236\u3002<br \/>\n\u4e00\u65e6\u78ba\u8a8d\u5b8c\u6210\uff0c\u8b93\u6211\u5011\u8207admin.py\u6587\u4ef6\u4e2d\u7684\u5167\u5bb9\u9032\u884c\u5c0d\u7167\u3002<\/p>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/78-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-22 8.16.38.png\" \/><\/div>\n<h2>\u7528\u6237\u521b\u5efa\u652f\u6301\u6a21\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u3002<\/h2>\n<p>\u4e3a\u4e86\u4fbf\u4e8e\u7406\u89e3\uff0c\u5c06\u5e94\u7528\u7a0b\u5e8f\u7684\u540d\u79f0\u547d\u540d\u4e3a&#8221;user&#8221;\u3002<\/p>\n<pre class=\"post-pre\"><code>docker-compose run --rm app sh -c \"python manage.py startapp user\"\r\n<\/code><\/pre>\n<p>\u5b8c\u6210\u5e94\u7528\u4e4b\u540e\uff0c\u5982\u540c\u5f80\u5e38\u4e00\u6837\uff0c\u5c06\u5176\u6ce8\u518c\u5230 settings.py \u6587\u4ef6\u4e2d\u3002<\/p>\n<p>\/django-api\/todo-project\/settings.py\u7684\u6587\u4ef6\u9700\u8981\u8fdb\u884c\u91cd\u65b0\u914d\u7f6e.<\/p>\n<pre class=\"post-pre\"><code>INSTALLED_APPS = [\r\n    'django.contrib.admin',\r\n    'django.contrib.auth',\r\n    'django.contrib.contenttypes',\r\n    'django.contrib.sessions',\r\n    'django.contrib.messages',\r\n    'django.contrib.staticfiles',\r\n    'rest_framework',               # \u3053\u308c\u304b\u3089\u4f7f\u3044\u307e\u3059\r\n    'rest_framework.authtoken',     # \u3053\u308c\u304b\u3089\u4f7f\u3044\u307e\u3059\r\n    'core',\r\n    'user',                         # \u8ffd\u52a0\r\n]\r\n<\/code><\/pre>\n<h3>\u521b\u5efa\u5e8f\u5217\u5316\u5668<\/h3>\n<h4>\u5e8f\u5217\u5316\u662f\u5c06\u5bf9\u8c61\u8f6c\u6362\u4e3a\u5b57\u8282\u6d41\u6216\u5b57\u7b26\u6d41\u7684\u8fc7\u7a0b\u3002<\/h4>\n<p>\u5c06\u590d\u6742\u6570\u636e\uff0c\u5982\u67e5\u8be2\u96c6\u548c\u6a21\u578b\u5b9e\u4f8b\uff0c\u8f6c\u6362\u4e3a\u53ef\u8f93\u51fa\u7684\u683c\u5f0f\uff0c\u5982JSON\u3001XML\u7b49\u3002\u7c7b\u4f3c\u4e8e\u5c06Django\u6a21\u578b\u7ffb\u8bd1\u6210\u4e0d\u540c\u683c\u5f0f\u7684\u64cd\u4f5c\u3002\u5c06\u6570\u636e\u6062\u590d\u5230\u539f\u59cb\u683c\u5f0f\u7684\u8fc7\u7a0b\u79f0\u4e3a\u53cd\u5e8f\u5217\u5316\u3002\uff08\u53c2\u8003\uff1aDjango REST framework \u5b98\u65b9\u6587\u6863\uff09<\/p>\n<p>\u7531\u4e8e\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u6ca1\u6709\u63d0\u4f9bserializers.py\u6587\u4ef6\uff0c\u56e0\u6b64\u9700\u8981\u81ea\u5df1\u521b\u5efa\u3002\u8def\u5f84\u4e3a\/django-api\/user\/serializers.py\u3002<\/p>\n<pre class=\"post-pre\"><code>from django.contrib.auth import get_user_model\r\n\r\nfrom rest_framework import serializers\r\n\r\n\r\nclass UserSerializer(serializers.ModelSerializer):\r\n    \"\"\"Serializer for the user object\"\"\"\r\n\r\n    class Meta:\r\n        model = get_user_model()\r\n        fields = ('email', 'password', 'name')\r\n        extra_kwargs = {'password': {'write_only': True, 'min_length': 8}}\r\n\r\n    def create(self, validated_data):\r\n        \"\"\"Create a new user with encrypted password and return it\"\"\"\r\n        user = get_user_model().objects.create_user(**validated_data)\r\n\r\n        return user\r\n<\/code><\/pre>\n<p>ModelSerializer<\/p>\n<p>Django \u306e\u30e2\u30c7\u30eb\u3068\u7d10\u3065\u3044\u3066\u3044\u307e\u3059\u3002\u30e2\u30c7\u30eb\u306b\u57fa\u3065\u3044\u3066\u30d5\u30a3\u30fc\u30eb\u30c9\u3068\u30d0\u30ea\u30c7\u30fc\u30bf\u304c\u81ea\u52d5\u7684\u306b Serializer \u306b\u3082\u9069\u7528\u3055\u308c\u307e\u3059\u3002\uff08Serializer \u306f\u3053\u308c\u306b\u9650\u3089\u305a\u6570\u7a2e\u985e\u7528\u610f\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u4f8b\u3048\u3070\u305f\u3060\u306e Serializer \u306f\u6700\u3082\u57fa\u672c\u7684\u306a\u30b7\u30ea\u30a2\u30e9\u30a4\u30b6\u3067\u3001\u5bfe\u8c61\u304c Django \u306e\u30e2\u30c7\u30eb\u3067\u3042\u308b\u5fc5\u8981\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u3053\u306e\u3042\u3068\u767b\u5834\u4e88\u5b9a\u3067\u3059\u3002\uff09<\/p>\n<p>get_user_model()<\/p>\n<p>get_user_model \u95a2\u6570\u306f\u3001\u305d\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067\u4f7f\u7528\u3057\u3066\u3044\u308b User \u30e2\u30c7\u30eb\u3092\u53d6\u5f97\u3057\u307e\u3059\u3002\u3064\u307e\u308a\u30c7\u30d5\u30a9\u30eb\u30c8\u306e User \u304b\u3001\u30ab\u30b9\u30bf\u30e0\u3057\u305f User \u304c\u8fd4\u308a\u307e\u3059\u3002\u6c4e\u7528\u7684\u306a\u51e6\u7406\u304c\u66f8\u3051\u308b\u3088\u3046\u306b\u306a\u308b\u306e\u3067\u3001\u30e6\u30fc\u30b6\u30fc\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\u3059\u308b\u3068\u304d\u306f get_user_model \u95a2\u6570\u3092\u4f7f\u3046\u3068\u3044\u3044\u3067\u3059\u306d\u3002<\/p>\n<h3>\u521b\u5efa\u89c6\u56fe<\/h3>\n<h4>\u89c2\u70b9\u662f\u4ec0\u4e48<\/h4>\n<p>View\u8d1f\u8d23\u6839\u636e\u5ba2\u6237\u7aef\uff08\u4f8b\u5982\u6d4f\u89c8\u5668\uff09\u7684\u8bf7\u6c42\u6765\u51b3\u5b9a\u8981\u6267\u884c\u4ec0\u4e48\u5904\u7406\uff08\u63d0\u4f9b\u54ea\u4e9bAPI\uff09\u3002\u8fd9\u4e2a\u5b9e\u73b0\u975e\u5e38\u7b80\u5355\u3002<\/p>\n<p>\/django-api\/user\/views.py\u7684\u4e2d\u6587\u91ca\u4e49<\/p>\n<pre class=\"post-pre\"><code>from rest_framework import generics\r\n\r\nfrom user.serializers import UserSerializer\r\n\r\n\r\nclass CreateUserView(generics.CreateAPIView):\r\n    \"\"\"Create a new user in the system\"\"\"\r\n    serializer_class = UserSerializer\r\n<\/code><\/pre>\n<p>\u5728`serializer_class`\u4e2d\u6307\u5b9a\u4e86\u5148\u524d\u521b\u5efa\u7684`UserSerializer`\u3002\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u521b\u5efa\u4e86\u5e8f\u5217\u5316\u5668\u548c\u89c6\u56fe\uff0c\u6682\u65f6\u6ca1\u95ee\u9898\u3002\u73b0\u5728\u6211\u4eec\u5c06\u521b\u5efa\u4e00\u4e2a\u65b0\u7684`urls.py`\u6587\u4ef6\u3002<\/p>\n<p>\/Django-API\/user\/urls.py \u53ef\u4ee5\u88ab\u6362\u6210\u4ee5\u4e0b\u7684\u4e2d\u6587\u8868\u8fbe\u65b9\u5f0f\uff1a<br \/>\n\/ Django-API \/ user \/ urls.py<\/p>\n<pre class=\"post-pre\"><code>from django.urls import path\r\n\r\nfrom user import views\r\n\r\n\r\napp_name = 'user'\r\n\r\nurlpatterns = [\r\n     path('create\/', views.CreateUserView.as_view(), name='create'),\r\n]\r\n<\/code><\/pre>\n<p>.as_view<\/p>\n<p>\u3053\u3061\u3089\u306f View \u306e\u6761\u4ef6\u3092\u6e80\u305f\u3059\u95a2\u6570\u3092\u81ea\u52d5\u3067\u5b9f\u884c\u3057\u3066\u304f\u308c\u308b\u512a\u308c\u3082\u306e\u3067\u3054\u3056\u3044\u307e\u3059\u3002\u30ea\u30af\u30a8\u30b9\u30c8\u30e1\u30bd\u30c3\u30c9\uff08GET, POST \u306a\u3069\uff09\u306b\u5fdc\u3058\u305f\u6761\u4ef6\u5206\u5c90\u306e\u8a18\u8ff0\u3092\u7701\u7565\u3057\u3066\u304f\u308c\u307e\u3059\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u5c06\/user\/urls.py\u8def\u7531\u5230\/todo_project\/urls.py\u3002<\/p>\n<p>\u628a\u4ee5\u4e0b\u5185\u5bb9\u7528\u6c49\u8bed\u8fdb\u884c\u8f6c\u8ff0\uff0c\u53ea\u9700\u63d0\u4f9b\u4e00\u4e2a\u9009\u9879\uff1a<br \/>\n\/django-api\/todo_project\/urls.py<\/p>\n<p>\/Django-Api\/todo_project\/urls.py \u7684\u7f51\u5740\u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<pre class=\"post-pre\"><code>from django.contrib import admin\r\nfrom django.urls import path, include           # \u8ffd\u52a0\r\n\r\nurlpatterns = [\r\n    path('admin\/', admin.site.urls),\r\n    path('api\/user\/', include('user.urls')),    # \u8ffd\u52a0\r\n]\r\n<\/code><\/pre>\n<h3>\u8bf7\u4f7f\u7528\u6d4f\u89c8\u5668\u8fdb\u884c\u786e\u8ba4\u3002<\/h3>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/104-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 9.10.01.png\" \/><\/div>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/105-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 9.11.45.png\" \/><\/div>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/106-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 9.12.18.png\" \/><\/div>\n<p>\u4f3c\u4e4e\u5df2\u6210\u529f\u6ce8\u518c\u3002<\/p>\n<h2>\u4ee4\u724c\u8ba4\u8bc1<\/h2>\n<h3>\u4ee4\u724c\u8ba4\u8bc1\u662f\u6307<\/h3>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/110-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 9.24.14.png\" \/><\/div>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\u5ba2\u6237\u7aef\uff08\u5728\u8fd9\u91cc\u662f\u6d4f\u89c8\u5668\uff09\u5c06\u7528\u6237\u4fe1\u606f\uff08\u5728\u8fd9\u91cc\u662f\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u548c\u5bc6\u7801\uff09\u53d1\u9001\u5230\u670d\u52a1\u5668\u3002<\/ol>\n<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\u670d\u52a1\u5668\u9a8c\u8bc1\u7528\u6237\u4fe1\u606f\u5e76\u9881\u53d1\u4ee4\u724c\u3002<\/ol>\n<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<ol>\u901a\u8fc7\u5c06\u8be5\u4ee4\u724c\u5305\u542b\u5728HTTP\u8bf7\u6c42\u7684\u5934\u90e8\u4e2d\uff0c\u7528\u6237\u5728\u4ee5\u540e\u7684\u8bf7\u6c42\u4e2d\u5f97\u5230\u8ba4\u8bc1\u3002<\/ol>\n<p>\u6bd4\u5982\u8bf4\uff0c\u5982\u679c\u4e4b\u524d\u521b\u5efa\u7684\u7528\u6237\u60f3\u8981\u66f4\u6539\u5bc6\u7801\uff0c\u6211\u4eec\u8981\u786e\u4fdd\u53ea\u6709\u7ecf\u8fc7\u8ba4\u8bc1\u7684\u7528\u6237\uff08\u672c\u4eba\uff09\u624d\u80fd\u8fdb\u884c\u66f4\u6539\u3002<br \/>\n\u9996\u5148\uff0c\u6211\u4eec\u8981\u5b9e\u65bd\u4ee4\u724c\u7684\u53d1\u884c\u3002<\/p>\n<p>\u4ee5\u4e0b\u662f\u5bf9\/django-api\/user\/serializers.py\u7684\u672c\u5730\u5316\u6c49\u8bed\u89e3\u91ca\uff1a<\/p>\n<p>\/django-api\/user\/serializers.py\u6587\u4ef6\u7684\u5185\u5bb9\u5982\u4e0b\u3002<\/p>\n<pre class=\"post-pre\"><code>from django.contrib.auth import get_user_model, authenticate  # \u8ffd\u52a0\r\n\r\nfrom rest_framework import serializers\r\n\r\n\r\nclass UserSerializer(serializers.ModelSerializer):\r\n\r\n# \u8ffd\u52a0\r\nclass AuthTokenSerializer(serializers.Serializer):\r\n    \"\"\"Serializer for the user authentication object\"\"\"\r\n    email = serializers.CharField()\r\n    password = serializers.CharField(\r\n        style={'input_type': 'password'},\r\n        trim_whitespace=False\r\n    )\r\n\r\n    def validate(self, attrs):\r\n        \"\"\"Validate and authenticate the user\"\"\"\r\n        email = attrs.get('email')\r\n        password = attrs.get('password')\r\n\r\n        user = authenticate(\r\n            request=self.context.get('request'),\r\n            username=email,\r\n            password=password\r\n        )\r\n        if not user:\r\n            msg = ('Unable to authenticate with provided credentials')\r\n            raise serializers.ValidationError(msg, code='authentication')\r\n\r\n        attrs['user'] = user\r\n        return attrs\r\n<\/code><\/pre>\n<p>\u8bbe\u5b9a\u4e00\u4e2a\u7528\u4e8e\u53d1\u653e\u4ee4\u724c\u6240\u9700\u7684\u7528\u6237\u4fe1\u606f\u5b57\u6bb5\uff08\u5305\u62ec\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\uff09\uff0c\u5e76\u5728\u9a8c\u8bc1\u51fd\u6570\u4e2d\u8fdb\u884c\u9a8c\u8bc1\u3002<br \/>\n\u5982\u679c\u8f93\u5165\u7684\u4fe1\u606f\u4e0d\u5339\u914d\uff0c\u5c06\u663e\u793a\u9519\u8bef\u6d88\u606f\u3002<\/p>\n<p>\/django-api\/user\/views.py \u7684\u4e2d\u6587\u91ca\u4e49<\/p>\n<pre class=\"post-pre\"><code>from rest_framework import generics\r\nfrom rest_framework.authtoken.views import ObtainAuthToken        # \u8ffd\u52a0\r\nfrom rest_framework.settings import api_settings                  # \u8ffd\u52a0\r\n\r\nfrom user.serializers import UserSerializer, AuthTokenSerializer  # \u8ffd\u52a0\r\n\r\n\r\nclass CreateUserView(generics.CreateAPIView):\r\n\r\n# \u8ffd\u52a0\r\nclass CreateTokenView(ObtainAuthToken):\r\n    \"\"\"Create a new auth token for user, restrict who can see Todo\"\"\"\r\n    serializer_class = AuthTokenSerializer\r\n    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES\r\n<\/code><\/pre>\n<p>renderer_classes<\/p>\n<p>\u30d6\u30e9\u30a6\u30b6\u4e0a\u3067\u767a\u884c\u3055\u308c\u305f\u30c8\u30fc\u30af\u30f3\u3092\u78ba\u8a8d\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\/django-api\/user\/urls.py \u53ef\u4ee5\u88ab\u7ffb\u8bd1\u4e3a\u300aDjango API \u7528\u6237 URL \u914d\u7f6e\u6587\u4ef6\u300b\u3002<\/p>\n<pre class=\"post-pre\"><code>from django.urls import path\r\n\r\nfrom user import views\r\n\r\n\r\napp_name = 'user'\r\n\r\nurlpatterns = [\r\n     path('create\/', views.CreateUserView.as_view(), name='create'),\r\n     path('token\/', views.CreateTokenView.as_view(), name='token'),    # \u8ffd\u52a0\r\n]\r\n<\/code><\/pre>\n<h3>\u8bf7\u5728\u6d4f\u89c8\u5668\u4e0a\u8fdb\u884c\u786e\u8ba4\u3002<\/h3>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/122-2.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 10.12.53.png\" \/><\/div>\n<p>\u8fd4\u56de\u4e86\u4e00\u4e2a\u4e0d\u89c4\u5219\u7684\u795e\u79d8\u5b57\u7b26\uff0c\u90a3\u5c31\u662f\u4ee4\u724c\u3002<\/p>\n<h3>\u66f4\u65b0\u7528\u6237\u4fe1\u606f<\/h3>\n<p>\u4e3a\u7ecf\u8fc7\u8ba4\u8bc1\u7684\u7528\u6237\u63d0\u4f9b\u66f4\u65b0\u5176\u6ce8\u518c\u4fe1\u606f\u7684\u529f\u80fd\u3002<\/p>\n<p>\/\u9910\u9986\u7f51\u7ad9\/API\/\u7528\u6237\/\u5e8f\u5217\u5316\u5668.py<\/p>\n<pre class=\"post-pre\"><code>class UserSerializer(serializers.ModelSerializer):\r\n    \"\"\"Serializer for the user object\"\"\"\r\n\r\n    class Meta:\r\n        model = get_user_model()\r\n        fields = ('email', 'password', 'name')\r\n        extra_kwargs = {'password': {'write_only': True, 'min_length': 8}}\r\n\r\n    def create(self, validated_data):\r\n        \"\"\"Create a new user with encrypted password and return it\"\"\"\r\n        user = get_user_model().objects.create_user(**validated_data)\r\n\r\n        return user\r\n\r\n    # \u8ffd\u52a0\r\n    def update(self, instance, validated_data):\r\n        \"\"\"Update a user, setting the password correctly and return it\"\"\"\r\n        password = validated_data.pop('password', None)\r\n        user = super().update(instance, validated_data)\r\n\r\n        if password:\r\n            user.set_password(password)\r\n            user.save()\r\n\r\n        return user\r\n<\/code><\/pre>\n<p>.pop(&#8216;password&#8217;)<\/p>\n<p>\u66f4\u65b0\u524d\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u3002\uff08\u7121\u3051\u308c\u3070 None \u304c\u8fd4\u3063\u3066\u304d\u307e\u3059\u3002\uff09<\/p>\n<p>\u4ee5\u4e0b\u662f\u201cdjango-api\/user\/views.py\u201d\u7684\u4e2d\u56fd\u672c\u571f\u5316\u91cd\u8ff0\u3002<\/p>\n<p>\/views.py\u662f\u7528\u6237\u89c6\u56fe\u7684\u6587\u4ef6\uff0c\u5728django-api\u4e2d\u3002<\/p>\n<pre class=\"post-pre\"><code>from rest_framework import generics, authentication, permissions  # \u8ffd\u52a0\r\nfrom rest_framework.authtoken.views import ObtainAuthToken\r\nfrom rest_framework.settings import api_settings\r\n\r\nfrom user.serializers import UserSerializer, AuthTokenSerializer\r\n\r\n\r\nclass CreateUserView(generics.CreateAPIView):\r\n\r\nclass CreateTokenView(ObtainAuthToken):\r\n\r\n\r\n# \u8ffd\u52a0\r\nclass ManageUserView(generics.RetrieveUpdateAPIView):\r\n    \"\"\"Manage the authenticated user\"\"\"\r\n    serializer_class = UserSerializer\r\n    authentication_classes = (authentication.TokenAuthentication,)\r\n    permission_classes = (permissions.IsAuthenticated,)\r\n\r\n    def get_object(self):\r\n        \"\"\"Retrieve and return authentication user\"\"\"\r\n        return self.request.user\r\n<\/code><\/pre>\n<p>authentication, permissions<\/p>\n<p>\u8aad\u3093\u3067\u5b57\u306e\u5982\u304f\u3001\u8a8d\u8a3c\u3068\u8a31\u53ef\u3092\u53f8\u308a\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u8a8d\u8a3c\u65b9\u6cd5\u306f\u30c8\u30fc\u30af\u30f3\u8a8d\u8a3c\u3092\u5229\u7528\u3057\u3001\u305d\u3057\u3066\u8a8d\u8a3c\u3055\u308c\u305f\u30e6\u30fc\u30b6\u30fc\u306e\u307f\u95b2\u89a7\u30fb\u7de8\u96c6\u3092\u8a31\u53ef\u3059\u308b\u3001\u3068\u3044\u3046\u3053\u3068\u3067\u3042\u308a\u307e\u3059\u3002\uff08\u72b6\u6cc1\u306b\u5fdc\u3058\u3066\u3001\u8a8d\u8a3c\u3055\u308c\u3066\u3044\u306a\u3044\u30e6\u30fc\u30b6\u30fc\u306f\u95b2\u89a7\u306e\u307f\u8a31\u53ef\u3001\u3068\u3044\u3063\u305f\u5236\u9650\u3082\u3067\u304d\u307e\u3059\u3002\uff09<\/p>\n<p>\/django-api\/user\/urls.py \u7684\u7ffb\u8bd1\u4e3a\u4e2d\u6587\u5982\u4e0b\uff1a\/django-api\/\u7528\u6237\/\u7f51\u5740.py<\/p>\n<pre class=\"post-pre\"><code>from django.urls import path\r\n\r\nfrom user import views\r\n\r\n\r\napp_name = 'user'\r\n\r\nurlpatterns = [\r\n    path('create\/', views.CreateUserView.as_view(), name='create'),\r\n    path('token\/', views.CreateTokenView.as_view(), name='token'),\r\n    path('update\/', views.ManageUserView.as_view(), name='update'),  # \u8ffd\u52a0\r\n]\r\n<\/code><\/pre>\n<h3>\u8bf7\u5728\u6d4f\u89c8\u5668\u4e2d\u786e\u8ba4\u3002<\/h3>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/135-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 10.33.14.png\" \/><\/div>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/136-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 10.43.09.png\" \/><\/div>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/137-2.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 10.51.49.png\" \/><\/div>\n<p>\u8f9b\u82e6\u4e86\uff0c\u4ee5\u4e0a\u662f\u6709\u5173\u7528\u6237\u5e94\u7528\u7a0b\u5e8f\u7684\u63cf\u8ff0\u3002\u6700\u540e\u6211\u4eec\u5c06\u521b\u5efa\u4e00\u4e2a\u5f85\u529e\u4e8b\u9879\u5e94\u7528\u7a0b\u5e8f\u3002\u6d41\u7a0b\u4e0e\u7528\u6237\u5e94\u7528\u7a0b\u5e8f\u51e0\u4e4e\u76f8\u540c\uff0c\u6240\u4ee5\u6211\u4eec\u4f1a\u5feb\u901f\u8fdb\u884c\u3002<\/p>\n<h2>\u5f85\u529e\u4e8b\u9879 API<\/h2>\n<p>\u901a\u8fc7\u4ee5\u4e0b\u6d41\u7a0b\u8fdb\u884c\uff1a\u6a21\u578b\u521b\u5efa \u2192 \u8fc1\u79fb \u2192 \u5e94\u7528\u521b\u5efa \u2192 \u5e94\u7528\u6ce8\u518c \u2192 \u5e8f\u5217\u5316\u5668 \u2192 \u89c6\u56fe \u2192 URL\u3002<\/p>\n<h3>\u521b\u5efaTodo\u6a21\u578b<\/h3>\n<p>\/django-api\/core\/models.py \u7684\u5185\u5bb9\u3002<\/p>\n<pre class=\"post-pre\"><code># \u6700\u4e0b\u90e8\u306b\u8ffd\u52a0\r\nclass Todo(models.Model):\r\n    \"\"\"Todo object\"\"\"\r\n    user = models.ForeignKey(\r\n        settings.AUTH_USER_MODEL,\r\n        on_delete=models.CASCADE\r\n    )\r\n\r\n    title = models.CharField(max_length=100)\r\n    content = models.CharField(max_length=255)\r\n    created_at = models.DateField(auto_now_add=True)\r\n    is_completed = models.BooleanField(default=False)\r\n\r\n    def __str__(self):\r\n        return self.title\r\n<\/code><\/pre>\n<p>settings.AUTH_USER_MODEL<\/p>\n<p>\u7e70\u308a\u8fd4\u3057\u306b\u306a\u308a\u307e\u3059\u304c\u4eca\u56de\u306f User \u30e2\u30c7\u30eb\u3092\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3057\u305f\u306e\u3067\u3001User \u30e2\u30c7\u30eb\u306e\u53c2\u7167\u6642\u306f\u305d\u308c\u3092\u53c2\u7167\u3059\u308b\u3088\u3046\u6307\u5b9a\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<p>\/django-api\/core\/admin.py \u7684\u5185\u5bb9\u8bf7\u8fdb\u884c\u540c\u4e49\u590d\u8ff0<\/p>\n<pre class=\"post-pre\"><code>admin.site.register(models.User, UserAdmin)\r\nadmin.site.register(models.Todo)  # \u6700\u4e0b\u90e8\u306b\u8ffd\u52a0\r\n<\/code><\/pre>\n<h3>\u8fc1\u79fb (Qian Yi)<\/h3>\n<p>\u5f53\u6a21\u578b\u53d1\u751f\u66f4\u6539\u65f6\uff0c\u8bf7\u4e0d\u8981\u5fd8\u8bb0\u8fdb\u884c\u8fc1\u79fb\u3002<\/p>\n<pre class=\"post-pre\"><code>$ docker-compose run --rm app sh -c \"python manage.py makemigrations core\"\r\nMigrations for 'core':\r\n  core\/migrations\/0002_todo.py\r\n    - Create model Todo\r\n<\/code><\/pre>\n<h3>\u521b\u5efa\u4e00\u4e2a\u5f85\u529e\u4e8b\u9879\u5e94\u7528\u7a0b\u5e8f<\/h3>\n<pre class=\"post-pre\"><code>$ docker-compose run --rm app sh -c \"python manage.py startapp todo\"\r\n<\/code><\/pre>\n<p>\u5728\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\u540e\uff0c\u8bf7\u786e\u4fdd\u6ce8\u518c\u5230 settings.py \u4e2d\u3002<\/p>\n<pre class=\"post-pre\"><code>INSTALLED_APPS = [\r\n    'django.contrib.admin',\r\n    'django.contrib.auth',\r\n    'django.contrib.contenttypes',\r\n    'django.contrib.sessions',\r\n    'django.contrib.messages',\r\n    'django.contrib.staticfiles',\r\n    'rest_framework',\r\n    'rest_framework.authtoken',\r\n    'core',\r\n    'user',\r\n    'todo',  # \u8ffd\u52a0\r\n]\r\n<\/code><\/pre>\n<h3>\u521b\u5efa\u5e8f\u5217\u5316\u5668<\/h3>\n<p>\/django-api\/todo\/serializers.py\uff08\u65b0\u5efa\uff09<\/p>\n<pre class=\"post-pre\"><code>from rest_framework import serializers\r\n\r\nfrom core.models import Todo\r\nfrom user.serializers import UserSerializer\r\n\r\nclass TodoSerializer(serializers.ModelSerializer):\r\n    \"\"\"Serializer for Todo objects\"\"\"\r\n\r\n    user = UserSerializer(read_only=True)\r\n\r\n    class Meta:\r\n        model = Todo\r\n        fields = ('id', 'user', 'title', 'content', 'created_at', 'is_completed')\r\n        read_only_fields = ('id', 'user',)\r\n<\/code><\/pre>\n<p>\u5173\u4e8e\u4e0eTodo\u6a21\u578b\u5173\u8054\u7684User\u6a21\u578b\u7684&#8221;user&#8221;\u5b57\u6bb5\uff0c\u5c06\u4f7f\u7528UserSerializer\u8fdb\u884c\u5e8f\u5217\u5316\u3002<\/p>\n<h3>\u521b\u5efa\u89c6\u56fe\u548c\u5206\u9875<\/h3>\n<p>\u4ee5\u4e0b\u662f\/views.py\u6587\u4ef6\u4e2d\u7684Django API\u4ee3\u7801\u3002<\/p>\n<p>\u8bf7\u7528\u4e00\u79cd\u65b9\u5f0f\u5c06\u5176\u7528\u4e2d\u6587\u8fdb\u884c\u91ca\u4e49\uff1a<\/p>\n<pre class=\"post-pre\"><code>from rest_framework import viewsets, generics, pagination, response\r\nfrom rest_framework.authentication import TokenAuthentication\r\nfrom rest_framework.permissions import IsAuthenticated\r\n\r\nfrom core.models import Todo\r\n\r\nfrom todo import serializers\r\n\r\n\r\nclass TodoPagination(pagination.PageNumberPagination):\r\n    \"\"\"Get 2 Todo items in a page\"\"\"\r\n    page_size = 2\r\n\r\n    def get_paginated_response(self, data):\r\n        return response.Response({\r\n            'next': self.get_next_link(),\r\n            'previous': self.get_previous_link(),\r\n            'count': self.page.paginator.count,\r\n            'total_pages': self.page.paginator.num_pages,\r\n            'current_page': self.page.number,\r\n            'results': data,\r\n            'page_size': self.page_size,\r\n            'range_first': (self.page.number * self.page_size) - (self.page_size) + 1,\r\n            'range_last': min((self.page.number * self.page_size), self.page.paginator.count),\r\n        })\r\n\r\n\r\nclass TodoViewSet(viewsets.ModelViewSet):\r\n    \"\"\"Handles creating, reading and updating todo items\"\"\"\r\n    authentication_classes = (TokenAuthentication,)\r\n    permission_classes = (IsAuthenticated,)\r\n    serializer_class = serializers.TodoSerializer\r\n    queryset = Todo.objects.order_by('-created_at')\r\n    pagination_class = TodoPagination\r\n\r\n    def perform_create(self, serializer):\r\n        \"\"\"Create a new Todo item\"\"\"\r\n        serializer.save(user=self.request.user)\r\n<\/code><\/pre>\n<p>pagination.PageNumberPagination<\/p>\n<p>\u30c7\u30d5\u30a9\u30eb\u30c8\u3067\u306f1\u30da\u30fc\u30b8\u3067\u5168\u4ef6\u53d6\u5f97\u3057\u3066\u3057\u307e\u3046\u305f\u3081\u3001\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u6a5f\u80fd\u3092\u8ffd\u52a0\u3057\u30661\u30da\u30fc\u30b8\u3042\u305f\u308a\u306e\u53d6\u5f97\u4ef6\u6570\u3092\u5236\u9650\u3057\u307e\u3059\u3002<br \/>\nresponse.Response \u306e\u4e2d\u8eab\u306f\u82f1\u5b57\u901a\u308a\u3067\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u3088\u308a\u3061\u3087\u3063\u3068\u898b\u6804\u3048\u304c\u3088\u304f\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>ModelViewSet<\/p>\n<p>\u57fa\u672c\u7684\u306a APIView \u304c\u5099\u308f\u3063\u3066\u3044\u307e\u3059\u3002\u3068\u3066\u3082\u4fbf\u5229\u3067\u3059\u3002<\/p>\n<p>\u4ee5\u4e0b\u4ec5\u4f9b\u53c2\u8003\u3002<\/p>\n<pre class=\"post-pre\"><code>.list()              # \u5168\u4ef6\u53d6\u5f97\r\n.retrieve()          # 1\u4ef6\u53d6\u5f97\r\n.create()            # \u4f5c\u6210\r\n.update()            # \u66f4\u65b0\r\n.partial_update()    # \u4e00\u90e8\u66f4\u65b0\r\n.destroy()           # \u524a\u9664\r\n<\/code><\/pre>\n<h3>\u521b\u5efa\u7f51\u5740<\/h3>\n<p>\/django-api\/todo\/urls.py\uff08\u521b\u5efa\u65b0\u6587\u4ef6\uff09<\/p>\n<pre class=\"post-pre\"><code>from django.urls import path, include\r\nfrom rest_framework.routers import DefaultRouter\r\n\r\nfrom todo import views\r\n\r\n\r\nrouter = DefaultRouter()\r\nrouter.register('todo', views.TodoViewSet)\r\n\r\napp_name = 'todo'\r\n\r\nurlpatterns = [\r\n    path('', include(router.urls))\r\n]\r\n<\/code><\/pre>\n<ul class=\"post-ul\">\n<li style=\"list-style-type: none;\">\n<ul class=\"post-ul\">DefaultRouter<\/ul>\n<\/li>\n<\/ul>\n<p>Router \u3092\u767b\u9332\u3067\u304d\u308b\u306e\u306f ViewSet \u306b\u9650\u308a\u307e\u3059\u3002user app \u3067\u4f5c\u6210\u3057\u305f generics \u306e view \u3068\u304b\u767b\u9332\u3057\u3088\u3046\u3082\u3093\u306a\u3089\u3061\u3083\u3093\u3068\u30a8\u30e9\u30fc\u767a\u751f\u3057\u307e\u3059\u3002<br \/>\nRouter \u306f\u3081\u3061\u3083\u3081\u3061\u3083\u4fbf\u5229\u3067\u3001\u8a73\u7d30\u306a API\uff08\/todo\/1\/ \u3068\u304b \/todo\/4\/\uff09\u3092\u81ea\u52d5\u7684\u306b\u4ed8\u52a0\u3057\u3066 URL \u767b\u9332\u3057\u3066\u304f\u308c\u307e\u3059\u3002\u308f\u3056\u308f\u3056 \/todo\/int:pk\/ \u307f\u305f\u3044\u306a\u3053\u3068\u66f8\u304b\u306a\u304f\u3066\u3044\u3044\u3093\u3067\u3059\u3002\u3059\u3054\u3044\u3002<\/p>\n<p>\/django-api\/todo_project\/urls.py \u7684\u5185\u5bb9\u8bf7\u8f6c\u8ff0\u4e3a\u4e2d\u6587\u3002<\/p>\n<pre class=\"post-pre\"><code>from django.contrib import admin\r\nfrom django.urls import path, include\r\n<\/code><\/pre>\n<p>urlpatterns = [<br \/>\npath(&#8216;admin\/&#8217;, admin.site.urls),<br \/>\npath(&#8216;api\/user\/&#8217;, include(&#8216;user.urls&#8217;)),<br \/>\npath(&#8216;api\/&#8217;, include(&#8216;todo.urls&#8217;)), # \u8ffd\u52a0<br \/>\n]<\/p>\n<p>urlpatterns = [<br \/>\npath(&#8216;admin\/&#8217;, admin.site.urls),<br \/>\npath(&#8216;api\/user\/&#8217;, include(&#8216;user.urls&#8217;)),<br \/>\npath(&#8216;api\/&#8217;, include(&#8216;todo.urls&#8217;)), # \u52a0\u5165<br \/>\n]<\/p>\n<p>urlpatterns = [<br \/>\npath(&#8216;admin\/&#8217;, admin.site.urls),<br \/>\npath(&#8216;api\/user\/&#8217;, include(&#8216;user.urls&#8217;)),<br \/>\npath(&#8216;api\/&#8217;, include(&#8216;todo.urls&#8217;)), # \u5305\u542b<br \/>\n]<\/p>\n<p>\u73b0\u5728\u672c\u6b21\u6311\u6218\u7684\u6240\u6709\u6d41\u7a0b\u5df2\u7ecf\u7ed3\u675f\u3002<br \/>\n\u6700\u540e\uff0c\u8ba9\u6211\u4eec\u5728\u6d4f\u89c8\u5668\u4e2d\u8fdb\u884c\u786e\u8ba4\u3002<\/p>\n<h3>\u8bf7\u4f7f\u7528\u6d4f\u89c8\u5668\u786e\u8ba4\uff08\u6700\u7ec8\u56de\uff09\u3002<\/h3>\n<p>\u4f7f\u7528docker-compose up\u547d\u4ee4\u53ef\u4ee5\u8bbf\u95ee\u5230http:\/\/127.0.0.1:8000\/api\/\u3002<br \/>\n\u8ba9\u6211\u4eec\u8bd5\u7740\u8df3\u8f6c\u5230&#8221;todo&#8221;: &#8220;http:\/\/127.0.0.1:8000\/api\/todo\/&#8221;\u3002<br \/>\n\uff08\u518d\u6b21\u5f3a\u8c03\uff0c\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u65e0\u6cd5\u67e5\u770b\u3002\uff09<\/p>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/174-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 11.59.04.png\" \/><\/div>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/175-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 11.56.46.png\" \/><\/div>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/176-0.png\" alt=\"\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8 2020-07-23 11.57.56.png\" \/><\/div>\n<h2>\u6982\u51b5<\/h2>\n<p>\u8fd9\u6b21\u6211\u4f7f\u7528 Docker \u642d\u5efa\u4e86\u5f00\u53d1\u73af\u5883\uff0c\u5e76\u5c1d\u8bd5\u4f7f\u7528 Django REST framework \u6765\u5b9e\u73b0 Todo \u5e94\u7528\u7684 API\u3002\u7531\u4e8e\u63a5\u89e6\u7684\u65b0\u4e1c\u897f\u5f88\u591a\uff0c\u6240\u4ee5\u4e0d\u80fd\u5b8c\u5168\u7406\u89e3\uff0c\u4f46\u662f\u6211\u80fd\u901a\u8fc7\u81ea\u5df1\u7684\u7814\u7a76\u5b8c\u6210\u5b83\uff0c\u611f\u5230\u975e\u5e38\u6ee1\u610f\u3002<\/p>\n<h2>\u8bf7\u53c2\u8003<\/h2>\n<p>\u4e66\u7c4d\u3001\u7f16\u7a0b\u548c\u6709\u65f6\u5019\u8ff7\u4f60\u732a<br \/>\nDjango\u5144\u5f1f\u535a\u5ba2<br \/>\n\u6a31\u82b1\u306e\u77e5\u8bc6Docker\u5165\u95e8<br \/>\nNarito\u535a\u5ba2<br \/>\nDjango\u5b98\u65b9\u6587\u6863<br \/>\nDjango REST\u6846\u67b6\u5b98\u65b9\u7f51\u7ad9<br \/>\nslideship Django REST\u6846\u67b6\u5b9e\u8df5\u5165\u95e8<br \/>\n\u6df1\u5165\u6d45\u51fa\u5730\u89e3\u91caDocker\u662f\u4ec0\u4e48<br \/>\n\u4f7f\u7528Python\u548cDjango\u6784\u5efa\u540e\u7aefREST API- \u521d\u5b66\u8005<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u9996\u5148 \u6700\u8fd1\u6211\u5728\u5b66\u4e60\u4f7f\u7528Docker\u548cDjango REST\u6846\u67b6\uff0c\u5c1d\u8bd5\u521b\u5efa\u4e00\u4e2aTodo\u5e94\u7528\u7684API\u3002\u6211\u4f1a\u5728\u8fd9\u91cc\u8bb0 [&hellip;]<\/p>\n","protected":false},"author":11,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-49901","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v21.5 (Yoast SEO v21.5) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API - Blog - Silicon Cloud<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.silicloud.com\/zh\/blog\/\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0-docker-\u548c-django-api\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API\" \/>\n<meta property=\"og:description\" content=\"\u9996\u5148 \u6700\u8fd1\u6211\u5728\u5b66\u4e60\u4f7f\u7528Docker\u548cDjango REST\u6846\u67b6\uff0c\u5c1d\u8bd5\u521b\u5efa\u4e00\u4e2aTodo\u5e94\u7528\u7684API\u3002\u6211\u4f1a\u5728\u8fd9\u91cc\u8bb0 [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.silicloud.com\/zh\/blog\/\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0-docker-\u548c-django-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog - Silicon Cloud\" \/>\n<meta property=\"article:published_time\" content=\"2023-11-27T09:43:44+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-30T08:37:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/16-0.png\" \/>\n<meta name=\"author\" content=\"\u65b0, \u97f5\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"\u65b0, \u97f5\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/\",\"name\":\"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API - Blog - Silicon Cloud\",\"isPartOf\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\"},\"datePublished\":\"2023-11-27T09:43:44+00:00\",\"dateModified\":\"2024-04-30T08:37:07+00:00\",\"author\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.silicloud.com\/zh\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/\",\"name\":\"Blog - Silicon Cloud\",\"description\":\"\",\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9\",\"name\":\"\u65b0, \u97f5\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g\",\"caption\":\"\u65b0, \u97f5\"},\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/author\/yunxin\/\"},{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/#local-main-organization-logo\",\"url\":\"\",\"contentUrl\":\"\",\"caption\":\"Blog - Silicon Cloud\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API - Blog - Silicon Cloud","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.silicloud.com\/zh\/blog\/\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0-docker-\u548c-django-api\/","og_locale":"zh_CN","og_type":"article","og_title":"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API","og_description":"\u9996\u5148 \u6700\u8fd1\u6211\u5728\u5b66\u4e60\u4f7f\u7528Docker\u548cDjango REST\u6846\u67b6\uff0c\u5c1d\u8bd5\u521b\u5efa\u4e00\u4e2aTodo\u5e94\u7528\u7684API\u3002\u6211\u4f1a\u5728\u8fd9\u91cc\u8bb0 [&hellip;]","og_url":"https:\/\/www.silicloud.com\/zh\/blog\/\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0-docker-\u548c-django-api\/","og_site_name":"Blog - Silicon Cloud","article_published_time":"2023-11-27T09:43:44+00:00","article_modified_time":"2024-04-30T08:37:07+00:00","og_image":[{"url":"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d8e02913a08637a6d47a6\/16-0.png"}],"author":"\u65b0, \u97f5","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"\u65b0, \u97f5","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"9 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/","url":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/","name":"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API - Blog - Silicon Cloud","isPartOf":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website"},"datePublished":"2023-11-27T09:43:44+00:00","dateModified":"2024-04-30T08:37:07+00:00","author":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9"},"breadcrumb":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.silicloud.com\/zh\/blog\/"},{"@type":"ListItem","position":2,"name":"\u8ba9\u6211\u4eec\u5c1d\u8bd5\u5b9e\u73b0 Docker \u548c Django API"}]},{"@type":"WebSite","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website","url":"https:\/\/www.silicloud.com\/zh\/blog\/","name":"Blog - Silicon Cloud","description":"","inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9","name":"\u65b0, \u97f5","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g","caption":"\u65b0, \u97f5"},"url":"https:\/\/www.silicloud.com\/zh\/blog\/author\/yunxin\/"},{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%ae%a9%e6%88%91%e4%bb%ac%e5%b0%9d%e8%af%95%e5%ae%9e%e7%8e%b0-docker-%e5%92%8c-django-api\/#local-main-organization-logo","url":"","contentUrl":"","caption":"Blog - Silicon Cloud"}]}},"_links":{"self":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/49901","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/comments?post=49901"}],"version-history":[{"count":2,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/49901\/revisions"}],"predecessor-version":[{"id":93043,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/49901\/revisions\/93043"}],"wp:attachment":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/media?parent=49901"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/categories?post=49901"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/tags?post=49901"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}