使用 Python、Django 和 Django Rest Framework 开发 Restful API
介绍
使用 Django Rest Framework 的 REST API
源代码
奖金
介绍
对于想要使用 Python、Django 和 Django Rest Framework 开发 RESTful API 项目的初学者来说,本文是一份权威指南。
-
Django是一个用Python编写的Web框架
-
Python是一种用于通用编程的解释型高级编程语言
-
API或应用程序编程接口是一组规则和机制,一个应用程序或组件通过这些规则和机制与其他应用程序或组件进行交互
-
REST或表述性状态转移是一种软件架构
REST API
正如 Roy Fielding 在一篇论文中所描述的那样,
REST 是一种“架构风格”,它基本上利用了现有的 Web 技术和协议。
简单来说,它是以适合客户端的格式呈现的数据。
因此,RESTful + API 是实现此类架构和约束(例如在 Web 服务中)的常用术语。
以下是来自 GitHub API 的一个GET请求示例
$ curl https://api.github.com/users/joshuadeguzman
您将看到类似如下的输出
{
"login": "joshuadeguzman",
"id": 20706361,
"node_id": "MDQ6VXNlcjIwNzA2MzYx",
"avatar_url": "https://avatars1.githubusercontent.com/u/20706361?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/joshuadeguzman",
"html_url": "https://github.com/joshuadeguzman",
"followers_url": "https://api.github.com/users/joshuadeguzman/followers",
"following_url": "https://api.github.com/users/joshuadeguzman/following{/other_user}",
"gists_url": "https://api.github.com/users/joshuadeguzman/gists{/gist_id}",
"starred_url": "https://api.github.com/users/joshuadeguzman/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/joshuadeguzman/subscriptions",
"organizations_url": "https://api.github.com/users/joshuadeguzman/orgs",
"repos_url": "https://api.github.com/users/joshuadeguzman/repos",
"events_url": "https://api.github.com/users/joshuadeguzman/events{/privacy}",
"received_events_url": "https://api.github.com/users/joshuadeguzman/received_events",
"type": "User",
"site_admin": false,
"name": "Joshua de Guzman",
"company": "@freelancer",
"blog": "https://joshuadeguzman.me",
"location": "Manila, PH",
"email": null,
"hireable": true,
"bio": "Android Engineer at @freelancer. Building tools for humans.",
"public_repos": 75,
"public_gists": 2,
"followers": 38,
"following": 10,
"created_at": "2016-07-28T15:19:54Z",
"updated_at": "2019-06-16T10:26:39Z"
}
上面显示的是JSON格式的数据集。
JSON或JavaScript 对象表示法是一种开放标准文件格式,它使用人类可读的文本来传输由属性值对和数组数据类型组成的数据对象。
其他格式包括 XML、INI、CSV 等。但如今,JSON 被广泛使用,因为它的结构直观,无论使用什么编程语言,都可以轻松读取和映射域对象。
Python 和 Django
Python的创始人 Guido van Rossum 认为,Python 是一个
高级编程语言,其核心设计理念是代码的可读性和允许程序员用几行代码表达概念的语法。
Python 使用类似英语的词汇表示法(例如方法、保留关键字和控制流),这使得任何初学者都能轻松上手。它还具有动态类型系统,这意味着它会在运行时验证程序的类型安全性。它还具有自动内存管理功能。
print(5 + 5) # This will result to 10
Django是一个高级 Python Web 框架,它使开发人员能够以简洁、实用的设计按时交付项目。
其旗舰功能包括快速开发的设计、安全和可扩展的产品。
Django 快速概览
Django 将更改传播到数据库模式的方式是通过其迁移模块。
示例User
模型
from django.db import models
class User(models.Model):
first_name = models.CharField(max_length=50)
middle_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
return self.name
如果您的模型有任何更改,请运行makemigrations
$ python manage.py makemigrations
最后,您可以将数据库与模型和迁移集同步
$ python manage.py migrate
使用 Django Rest Framework 的 REST API
DRF,即 Django REST 框架,是一个强大而灵活的 Web API 构建工具包。它可以帮助开发人员避免自己从头开始构建复杂而可靠的 REST API,从而避免重复造轮子。因为随着项目变得越来越复杂,您很快就会意识到使用 DRF 或其他实用 REST 框架的必要性。
1. 安装和项目设置
创建项目目录
$ mkdir djangoapi
通过pip安装virtualenv
虚拟环境使项目能够在其环境中拥有额外的库或对包进行更改,而不会干扰全局或其他环境的库。
pip
是一个用Python编写的用于安装和管理软件包的包管理系统。
$ pip install virtualenv
在项目目录中创建环境文件夹
$ cd djangoapi
$ virtualenv venv
激活环境
$ source venv/bin/activate
要撤消对路径的这些更改,只需运行deactivate
。有关virtualenv 的更多信息。
安装django、djangorestframework
$ pip install django
$ pip install djangorestframework
创建django 项目
$ django-admin startproject blog
运行你的项目
$ python manage.py runserver
System check identified no issues (0 silenced).
You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
August 16, 2018 - 09:58:36
Django version 2.1, using settings 'blog.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
未应用的迁移是指启动 django 项目时包含的默认迁移文件。
要同步这些迁移文件,只需运行migrate
$ python manage.py migrate
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
我们项目中的默认数据库当前设置为名为的 SQLite db.sqlite3
。
创建django 项目的应用程序
$ cd blog
$ python manage.py startapp posts
项目结构应该是这样的
$ find .
./posts
./posts/migrations
./posts/migrations/__init__.py
./posts/models.py
./posts/__init__.py
./posts/apps.py
./posts/admin.py
./posts/tests.py
./posts/views.py
./db.sqlite3
./blog
./blog/__init__.py
./blog/__pycache__
./blog/__pycache__/settings.cpython-36.pyc
./blog/__pycache__/wsgi.cpython-36.pyc
./blog/__pycache__/__init__.cpython-36.pyc
./blog/__pycache__/urls.cpython-36.pyc
./blog/settings.py
./blog/urls.py
./blog/wsgi.py
./manage.py
2. 模型
每个模型实例都是数据信息的可靠来源。通常,每个模型都对应数据库中的一个表。
# djangoapi/blog/posts/models.py
from django.db import models
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
is_featured = models.BooleanField(default=False)
def __str__(self):
return self.name
__str__
由str()
内置函数和打印语句调用来计算对象的“非正式”字符串表示。
如果您尝试运行makemigrations
,django 将不会看到这些更改。
$ No changes detected
为了解决此问题,请将您的posts
应用添加到项目的已安装应用中。
# djangoapi/blog/blog/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts' # Add it here
]
继续模型迁移
$ python manage.py makemigrations
Migrations for 'posts':
posts/migrations/0001_initial.py
- Create model Post
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, posts, sessions
Running migrations:
Applying posts.0001_initial... OK
3.序列化
序列化器允许将数据结构或对象状态转换为可以存储或传输并在以后重建的格式。
创建 APIserializers.py
和views.py
文件并像这样隔离它们
# posts/api
posts/api/serializers.py
posts/api/views.py
# posts/migrations
posts/migrations/
# posts
posts/admin.py
posts/apps.py
posts/models.py
posts/tests.py
posts/views.py
# posts/api/serializers.py
from ..models import Post
from rest_framework import serializers
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('title', 'content', 'is_featured') # if not declared, all fields of the model will be shown
在本教程中,我们使用了有关此内容ModelSerializer
的更多内容。
4. 视图
视图函数(或简称视图)是一个接受 Web 请求并返回 Web 响应的 Python 函数。
# posts/api/views.py
from ..models import Post
from . import serializers
from rest_framework import generics, status
from rest_framework.response import Response
class PostListView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = serializers.PostSerializer
如上所示,ListAPIView
用于只读端点来表示模型实例的集合。
在此代码片段中,我们使用了generics
来自的视图方法rest_framework
,有关更多信息请参见此。
5. URL
在这里,我们设置我们的路线或 URL 路径到我们指定的视图,我们期望每个视图都有特定的响应。
# posts/urls.py
from django.urls import path
from . import views
from .api import views
urlpatterns = [
path('', views.PostListView.as_view(), name=None)
]
6. 完成设置
确保rest_framework
已添加到我们项目的应用程序中。
# djangoapi/blog/blog/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # Add it here
'posts'
]
7. Django 管理员
由于我们尚未设置POST
请求,我们将通过 django 的管理面板填充数据库。
为此,请创建一个admin
带有密码的超级用户帐户1234password
。
$ python manage.py createsuperuser --email admin@example.com --username admin
Password:
Password (again):
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
在管理面板中注册模型。
# posts/admin.py
from django.contrib import admin
from .models import Post
# Register your models here.
admin.site.register(Post)
就这样。访问管理面板并更新posts
模型记录。更多信息请参见。
8.测试我们的API
$ python manage.py runserver
GET /api/v1/posts/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"title": "Example Post #1",
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"is_featured": false
},
{
"title": "Example Post #2",
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"is_featured": true
}
]
太好了。现在我们该更新视图并完成标准的 CRUD 操作了。
9. 添加更多视图
POST
是一种用于在数据库中创建(有时更新)资源的方法。
# posts/api/views.py
from ..models import Post
from . import serializers
from rest_framework import generics, status
from rest_framework.response import Response
class PostCreateView(generics.CreateAPIView):
queryset = Post.objects.all()
serializer_class = serializers.PostSerializer
def create(self, request, *args, **kwargs):
super(PostCreateView, self).create(request, args, kwargs)
response = {"status_code": status.HTTP_200_OK,
"message": "Successfully created",
"result": request.data}
return Response(response)
通常,当我们想要公开数据集列表时,我们会分离List
和查看类,同时轻松阻止某个请求或在数据库中为该特定视图创建资源。Create
POST
List
用例总是因应用程序而异,您可以选择使用ListCreateAPIView甚至ViewSets来组合一组相关视图的逻辑。
可选:由于我们希望以更系统的方式显示数据,因此我们覆盖create
方法并映射内联自定义响应处理程序。
添加更多带有方法的视图GET
,以处理特定的博客文章详细信息。PATCH
DELETE
class PostDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = serializers.PostSerializer
def retrieve(self, request, *args, **kwargs):
super(PostDetailView, self).retrieve(request, args, kwargs)
instance = self.get_object()
serializer = self.get_serializer(instance)
data = serializer.data
response = {"status_code": status.HTTP_200_OK,
"message": "Successfully retrieved",
"result": data}
return Response(response)
def patch(self, request, *args, **kwargs):
super(PostDetailView, self).patch(request, args, kwargs)
instance = self.get_object()
serializer = self.get_serializer(instance)
data = serializer.data
response = {"status_code": status.HTTP_200_OK,
"message": "Successfully updated",
"result": data}
return Response(response)
def delete(self, request, *args, **kwargs):
super(PostDetailView, self).delete(request, args, kwargs)
response = {"status_code": status.HTTP_200_OK,
"message": "Successfully deleted"}
return Response(response)
10.更新URL
# posts/urls.py
from django.urls import path
from . import views
from .api import views
urlpatterns = [
path('', views.PostListView.as_view(), name=None),
path('create/', views.PostCreateView.as_view(), name=None),
path('<int:pk>/', views.PostDetailView.as_view(), name=None)
]
现在您可以通过Postman、您的应用程序向您的 API 发送请求,或者GET
从您的浏览器发出请求,例如:
POST /api/v1/posts/create/
HTTP 200 OK
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept
{
"status_code": 200,
"message": "Successfully created",
"result": {
"csrfmiddlewaretoken": "rnSUN3XOIghnXA0yKghnQgxg0do39xhorYene5ALw3gWGThK5MjG6YjL8VUb7v2h",
"title": "Creating a resource",
"content": "Howdy mate!"
}
}
GET /api/v1/posts/1/
HTTP 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"status_code": 200,
"message": "Successfully retrieved",
"result": {
"title": "Sample Post",
"content": "Sample Post Content",
"is_featured": false
}
}
就这样!您已经成功使用 DRF 开发 RESTful API 了!干杯!
源代码
可在GitHub上获取。
奖金
我将介绍另一篇文章,介绍使用JSON Web 令牌进行 RESTful 身份验证的可测试 RESTful API ,并很快在此处添加链接,敬请关注!
如有疑问或建议,请随时评论或联系我。
文章来源:https://dev.to/joshuamdeguzman/definitive-guide-developing-restful-apis-using-python-django-and-drf-2h7e