Django官方文档
django2集成DjangoUeditor富文本编辑器
REST 即表述性状态传递(Representational State Transfer),它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。REST通常基于使用HTTP,URI,和XML以及HTML这些现有的广泛流行的协议和标准。
RESTful API 设计规范
官方网站
中文文档
RESTful API四大基本原则:
django-RESTful 需要以下包支持(除了主插件程序包外,其他的包为可选项)
可以根据需要安装相应的包
pip install djangorestframework
pip install markdown # 为browsable API 提供Markdown支持。
pip install django-filter # Filtering支持。
使用 django-RESTful 需要注册应用到 settings.py 的 INSTALLED_APPS 中
INSTALLED_APPS = [
...
'rest_framework',
]
REST framework API的所有全局设定都会放在一个叫REST_FRAMEWORK的配置词典里,并添加到 settings.py 中:
REST_FRAMEWORK = {
# 在这里配置访问许可
'DEFAULT_PERMISSION_CLASSES': [
# 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' # 匿名只读,登录用户可用
'rest_framework.permissions.IsAdminUser', # 只能管理员使用
],
# 配置分页器
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
如果打算用browsable API(一个可视化API测试工具),可能也会用REST framework的登录注销视图。可以添加路由到根目录的urls.py文件
urlpatterns = [
...
path('api-auth/', include('rest_framework.urls')) # 路由路径可以更改
]
以一个实例进行测试:创建一个读写API来访问项目的用户信息。
在根目录的 urls.py 中创建API
# urls.py
from django.urls import path, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
# 序列化器是用来定义API的表示形式。
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'is_staff']
# ViewSets定义视图的行为。
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 路由器提供一个简单自动的方法来决定URL的配置。
router = routers.DefaultRouter()
router.register(r'users', UserViewSet) # 注册路由
# 通过URL自动路由来给我们的API布局。
# 此外,我们还要把登录的URL包含进来。
urlpatterns = [
path('', include(router.urls)), # 注册 REST 路由到主路由
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
现在可以在浏览器中打开(默认页,即第一条路由)http://127.0.0.1:8000/,查看 ‘user’ API了。如果使用了右上角的登录控制,还可以在系统中添加、创建并删除用户。这样就是安装和配置成功了。
在实际项目中,django-RESTful 的使用分为三个步骤:
定义序列化程序,可以创建一个新的文件,这里使用 serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
# 定义序列化处理器,继承自 serializers.HyperlinkedModelSerializer,使用超链接关系
class UserSerializer(serializers.ModelSerializer):
class Meta:
# model 定义使用的数模型
model = User
# fields 定义使用数据模型的哪些字段
fields = ('url', 'username', 'email', 'groups')
django-RESTful 提供了3个序列化类的模板: Serializer、ModelSerializer、HyperlinkedModelSerializer
create(**validate_data)
和 update(instance, **validate_data)
两个函数django-RESTful 提供了一些预设的视图处理类
from rest_framework import viewsets
from django.contrib.auth.models import User
from .serializers import UserSerializer
# 视图处理类
class UserViewSet(viewsets.ModelViewSet):
# queryset 为查询的结果集合
queryset = User.objects.all()
# serializer_classs 使用的序列化器
serializer_class = UserSerializer
可以在应用中创建路由,并注册到主路由中
# 应用中的 urls.py
from django.urls import path, include
from rest_framework import routers
# 路由器提供一个简单自动的方法来决定URL的配置。
# 创建路由器
router = routers.DefaultRouter()
# 在路由器中注册路由及处理器(FBV或CBV)
router.register(r'users', UserViewSet)
# 通过URL自动路由来给我们的API布局。
urlpatterns = [
path('', include(router.urls)), # 将 REST 路由器中的路由添加到 app 的路由中
path('api-auth/', include('rest_framework.urls')), # 添加 browsable API 的登录路由
]
根据实际情况自定义序列化器或者使用自定义的视图函数,有一些需要使用到的
在自定义的视图中,需要将数据通过序列化器序列化后发出响应,接收到的请求也需要通过反序列化获取具体数据
from .serializers import UserSerializer
from django.contrib.auth.models import User
s1 = UserSerializer(User.objects.get(pk=1)) # 序列化单条数据
s2 = UserSerializer(User.objects.all(), many=True) # 序列化多条数据
# 渲染成Json字符串
from rest_framework.renderers import JSONRenderer
content = JSONRenderer().render(s1.data)
# 对已经渲染的Json字符串反序列化为Json对象
data = JSONParser().parse(io.BytesIO(content))
# 或直接解析 request 对象(POST)
# from rest_framework.parsers import JSONParser
# data = JSONParser().parse(request)
# serializer = UserSerializer(data=data) # 根据提交的参数获取序列化对象
# if serizlizer.is_valid(): # 通过验证
# serializer.save() # 保存数据
在查看和测试API的过程中,会发现某些数据表的外键指向的是关联表的数据链接,而不是数据内容。如果要使用数据内容,就需要将关联关系序列化。在定义序列化器时,将外键字段声明成为字符串关系字段即可。
from django.contrib.auth.models import User
from rest_framework import serializers
# 定义序列化处理器,继承自 serializers.HyperlinkedModelSerializer,使用超链接关系
class UserSerializer(serializers.HyperlinkedModelSerializer):
# 在此定义字段
# 定义关系字段,将数据信息字符串化
groups = serializers.StringRelatedField() # 如果是对多关系(对方表是多端)则需要参数 many=True
# 也可以将关系对象整体序列化(即返回的 json 中,此字段是给包含了所有数据的 json 对象)
# groups = GroupSerializer() # 需先定义 GroupSerializer 序列化器,且如果对方是多端也需要 many=True
class Meta:
# model 定义使用的数模型
model = User
# fields 定义使用数据模型的哪些字段
fields = ('url', 'username', 'email', 'groups')
这个方法在一对一、一对多、多对多关系都适用。如果对方是多端(即此表的该外键字段或反查字段有多个数据),添加参数 many=True 即可。其中一些关联字段类型为
使用的封装好的django-RESTful视图处理类能够方便的获取请求返回响应,但是如果需要使用自定义的视图处理器,则可使用 @api_view
装饰器(FBV)或 APIView
基类(CBV)。
FBV 方式举例,需注意的是注册路由使用 path 方法直接到 urlpatterns
from rest_framework.decorators import api_view
from .serializers import UserSerializer
from rest_framework.response import Response
from rest_framework.parsers import JSONParser
from django.contrib.auth.models import User
from django.http import JsonResponse
@api_view(['GET', 'POST'])
def user_func(request, pk=None):
if request.method == 'GET':
if not pk:
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True, context={'request': request})
else:
queryset = User.objects.get(pk=pk)
serializer = UserSerializer(queryset, context={'request': request})
# django-RESTful 重新封装了 Response,可以直接序列化
# 可以根据请求类型返回数据,例如浏览器直接请求会返回管理页面,请求 json 格式则返回 json 数据
# 也可以在请求地址后添加参数 ?format=json 指定获取 json 数据或 api 页面
return Response(serializer.data)
# return JsonResponse(serializer.data) # 返回的是序列化后的json字符串
elif request.method == 'POST':
# 接收的 request 是 django-RESTful 重新封装后的 request 对象
# 可以直接将其内容反序列化,然后通过序列化器从数据库中查询相关数据,再进行序列化
data = JSONParser().parse(request)
serializer = UserSerializer(data, context={'request': request})
# 序列化器对象可以进行验证
if serializer.is_valid():
serializer.save() # 保存至数据库
return Response(serializer.data, status=201)
else:
return Response(serializer.errors, status=400)
CBV 方式举例,需注意的是注册路由使用 path 方法直接到 urlpatterns
from rest_framework.views import APIView
from .serializers import UserSerializer
from django.contrib.auth.models import User
from rest_framework.response import Response
from rest_framework.parsers import JSONParser
class UserClass(APIView):
def get(self, request, pk=None):
if not pk:
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True, context={'request': request})
else:
queryset = User.objects.get(pk=pk)
serializer = UserSerializer(queryset, context={'request': request})
return Response(serializer.data)
def post(self,request):
data = JSONParser().parse(request)
serializer = UserSerializer(data, context={'request': request})
# 序列化器对象可以进行验证
if serializer.is_valid():
serializer.save() # 保存至数据库
return Response(serializer.data, status=201)
else:
return Response(serializer.errors, status=400)
rest_framework 的 request 和 django 的 request 不太一样,获取数据是使用 request.data
,类似于 django 的 request.body
但是不是字节码,而是字符串。
name = request.data.get('name', None)
默认情况下, APIView 中的相关接口方法不验证权限(授权),对资源并不安全,所以需要增加验证。
首先在 settings.py 中的 REST_FRAMEWORK 字段配置权限访问许可
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [ # 默认使用的授权认证
'rest_framework.authentication.BasicAuthentication', # 基本授权认证
'rest_framework.authentication.SessionAuthentication', # 基于session的授权认证
]
}
然后可以在视图中指定验证方式和许可类型
class EcampleView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication) # 验证方式
permission_classes = (IsAuthenticated,) # 许可类型
def get(self, request):
pass
但是这种授权是基于 session 登录的,即 auth 模块的认证。在 api 接口中,通常会使用 token 进行认证。
TokenAuthentication 提供了简单的基于 Token 的HTTP认证方案,适用于客户端 - 服务器设置,如本地桌面和移动客户端。要在 django-RESTful 中使用 TokenAuthentication,需要配置认证类包含 TokenAuthentication,另外需要注册 rest_framework.authtoken 这个 app。需注意的是,确保在修改设置后运行一下 manage.py migrate
,因为 rest_framework.authtoken 会提交一些数据库迁移操作。
# settings.py
INSTALLED_APPS = [
...
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [ # 默认使用的授权认证
'rest_framework.authentication.TokenAuthentication', # token授权认证
]
}
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
user = User.objects.get(pk=1) # 获取用户
token = Token.objects.create(user=user) # 根据用户创建 token 实例
print(token.key) # token.key 就是需要验证的字段
通常会在每个用户创建时,创建对应的 token,可以捕捉用户的 post_save 信号
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
也可以为现有用户生成令牌
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
for user in User.objects.all():
Token.objects.get_or_create(user=user)
# 此方法可以返回2个值,分别为 token 对象和 created
对客户端进行身份验证,token需要包含在名为 Authorization 的HTTP头中。密钥应该是以字符串"Token"为前缀,以空格分割的两个字符串。例如:
function ajax_get() {
fetch('/api/user/, {
headers: {
'Authorization': 'Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
}
}).then(response=>response.json())
.then(data=>{
console.log(data)
})
}
如果认证成功,TokenAuthentication 提供以下认证信息:
那些被拒绝的未经身份验证的请求会返回使用适当WWW-Authenticate标头的HTTP 401 Unauthorized响应。例如:
WWW-Authenticate: Token
当使用TokenAuthentication时,可能希望为客户端提供一个获取给定用户名和密码的令牌的机制。 REST framework 提供了一个内置的视图来提供这个功能。要使用它,需要将 obtain_auth_token 视图添加到你的URLconf:
from rest_framework.authtoken import views
urlpatterns += [
path('api-token-auth/', views.obtain_auth_token) # url 路由可以自定义
]
当使用form表单或JSON将有效的username和password字段POST提交到视图时,obtain_auth_token 视图将返回JSON响应:
{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
请注意,默认的obtain_auth_token视图显式使用JSON请求和响应,而不是使用settings中配置的默认渲染器和解析器类。如果需要自定义版本的obtain_auth_token视图,可以通过重写ObtainAuthToken类,并在url conf中使用它来实现。默认情况下,没有权限或限制应用于obtain_auth_token视图。如果你希望应用限制,则需要重写视图类,并使用throttle_classes属性包含它们。
django 有组件支持发送邮件
发送邮件需要配置邮件服务器信息
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'emailPassword'
需注意的是 EMAIL_HOST_PASSWORD 使用的是邮件服务器的授权码而不是登录密码。
django 使用 django.core.mail.send_mail()
发送邮件,其用法为
from django.core.mail import send_mail
send_mail(title, message, from_email, recipient_list, fail_silently, auth_user, auth_password, connection, html_message)
可以使用 unittest 库进行单元测试。创建测试类,继承自 unittest 库中的相应类,然后创建方法。方法可以独立执行,用作测试使用。单元测试的方便之处在于可以直接调用已经写好的代码,或测试写好的代码。注意单元测试的方法名以test为开头,如果不以test开头则不会进行测试。
from django.test import TestCase
import unittest
class UserTestCase(TestCase):
def setUp(self):
print('--执行测试前进行配置--')
def test_01_add(self):
print('--add order--')
def test_02_get_info(self):
print('--info--')
def tearDown(self):
print('--测试后进行释放资源等收尾工作--')
if __name__ == '__main__':
unittest.main() # 执行单个测试
执行顺序为:
除了直接执行测试类,也可以创建套件执行
from unittest import TestSuite, TextTestRunner
def suite(): # 声明套件类
suite_ = TestSuite() # 创建测试套件对象
suite_.addTest(UserTestCase.test_01_add) # 添加套件的测试方法
suite_.addTest(UserTestCase.test_02_get_info)
return suite_
if __name__ == '__main__':
runner = TextTestRunner()
runner.run(suite())
多个套件可以按照排序来进行不同的测试类的测试
def suite1(): # 套件类1
suite_ = TestSuite() # 创建测试套件对象
suite_.addTest(UserTestCase.test_01_add) # 添加套件的测试方法
suite_.addTest(UserTestCase.test_02_get_info)
return suite_
def suite2(): # 套件类2
suite_ = TestSuite() # 创建测试套件对象
suite_.addTest(OrderTestCase.test_01_add) # 添加套件的测试方法
suite_.addTest(OrderTestCase.test_02_get_info)
if __name__ == '__main__':
TextTestRunner().run(TestSuite((suite1(), suite2()))) # 按顺序进行测试
django 测试模型不会使用实际数据库, 会为测试创建单独的空白数据库。所以进行模型测试需要先在 setUp()
方法中创建模型数据,进行数据初始化。当测试正常结束后,无论结果如何,会将临时创建的数据库销毁。
django 在TestCase对象中定义了Client类用于模拟客户端发送请求,所以可以使用这个工具来测试接口或视图。
def test_api(self):
response = self.client.post('/api')
self.assertEqual(r.status_code, 200)
content = json.loads(r.content)
self.assertEqual(content['result'], True)
client 可以使用 get 、post、put 等常用发放模拟客户端发送请求,这些方法的格式基本一致:post(path, data, content_type, follow, secure)
。其参数含义为: