帮助使用通道在websockets之上构建restful api。
channels_api的Python项目详细描述
通道API
channels api使用 频道。它提供了一个与django相当的ResourceBinding。 rest框架的ModelViewSet。它基于drf序列化程序 上课。
它需要python 2.7或3.x、channels<;=1.1.8.1、django<;=1.11和django rest framework 3.x
从我在SF Django Meetup或PyBay 2016的演讲中,您可以了解有关channels api的更多信息
它是如何工作的?
api构建在通道WebsocketBinding类之上。它的工作原理是 客户端发送一个stream和payload参数。这允许 我们将消息路由到特定的不同流(或资源) 行动。因此POST /user将有一条如下所示的消息
varmsg={stream:"users",payload:{action:"create",data:{email:"test@example.com",password:"password"}}}ws.send(JSON.stringify(msg))
为什么?
您已经在使用django rest框架,并希望公开类似的 基于websockets的逻辑。
websockets可以向客户端发布更新而无需请求。这是 当一个资源可以被跨多个平台的多个用户编辑时非常有用。
开始
本教程假设您熟悉频道并已完成 Getting Started
- 将channels_api添加到requirements.txt
pip install channels_api
- 将channels_api添加到INSTALLED_APPS
INSTALLED_APPS=('rest_framework','channels','channels_api')
- 添加第一个资源绑定
# polls/bindings.pyfromchannels_api.bindingsimportResourceBindingfrom.modelsimportQuestionfrom.serializersimportQuestionSerializerclassQuestionBinding(ResourceBinding):model=Questionstream="questions"serializer_class=QuestionSerializerqueryset=Question.objects.all()
- 将WebsocketDemultiplexer添加到channel_routing
# proj/routing.pyfromchannels.generic.websocketsimportWebsocketDemultiplexerfromchannels.routingimportroute_classfrompolls.bindingsimportQuestionBindingclassAPIDemultiplexer(WebsocketDemultiplexer):consumers={'questions':QuestionBinding.consumer}channel_routing=[route_class(APIDemultiplexer)]
就这样。现在可以向服务器发出rest websocket请求。
varws=newWebSocket("ws://"+window.location.host+"/")ws.onmessage=function(e){console.log(e.data)}varmsg={stream:"questions",payload:{action:"create",data:{question_text:"What is your favorite python package?"},request_id:"some-guid"}}ws.send(JSON.stringify(msg))// response {stream:"questions",payload:{action:"create",data:{id:"1",question_text:"What is your favorite python package"}errors:[],response_status:200request_id:"some-guid"}}
- 添加频道调试器页(可选)
此页有助于调试来自浏览器的API请求,并查看 回应。它只在DEBUG=TRUE时使用。
# proj/urls.pyfromdjango.conf.urlsimportincludeurlpatterns=[url(r'^channels-api/',include('channels_api.urls'))]
资源绑定
默认情况下,ResourceBinding实现以下rest方法:
- create
- retrieve
- update
- list
- delete
- subscribe
有关每个方法的使用示例,请参见测试套件。
列表分页
分页由django.core.paginator.paginator处理
您可以通过重写设置来配置DEFAULT_PAGE_SIZE。
# settings.pyCHANNELS_API={'DEFAULT_PAGE_SIZE':25}
订阅
订阅是以编程方式接收更新的一种方式 每当创建、更新或删除资源时,从服务器
默认情况下,channels api实现了以下订阅
- 创建资源
- 更新任何资源
- 更新此资源
- 删除任何资源
- 删除此资源
要订阅特定事件,只需使用subscribe操作 使用要筛选的参数
// get an event when any question is updated varmsg={stream:"questions",payload:{action:"subscribe",data:{action:"update"}}}// get an event when question(1) is updated varmsg={stream:"questions",payload:{action:"subscribe",pk:"1",data:{action:"update"}}}
自定义操作
要添加自己的自定义操作,请使用detail_action或list_action 装饰师。
fromchannels_api.bindingsimportResourceBindingfromchannels_api.decoratorsimportdetail_action,list_actionfrom.modelsimportQuestionfrom.serializersimportQuestionSerializerclassQuestionBinding(ResourceBinding):model=Questionstream="questions"serializer_class=QuestionSerializerqueryset=Question.objects.all()@detail_action()defpublish(self,pk,data=None,**kwargs):instance=self.get_object(pk)result=instance.publish()returnresult,200@list_action()defreport(self,data=None,**kwargs):report=self.get_queryset().build_report()returnreport,200
然后在消息中将方法名作为“action”传递
// run the publish() custom action on Question 1 varmsg={stream:"questions",payload:{action:"publish",data:{pk:"1"}}}// run the report() custom action on all Questions varmsg={stream:"questions",payload:{action:"report"}}
权限
channels api提供了一个受rest_框架启发的简单的权限类系统。 提供了两个权限类:AllowAny和IsAuthenticated。
要全局配置权限,请使用设置DEFAULT_PERMISSION_CLASSES,如下所示
# settings.pyCHANNELS_API={'DEFAULT_PERMISSION_CLASSES':('channels_api.permissions.AllowAny',)}
您还可以像这样在ResourceBinding本身上配置权限类
fromchannels_api.permissionsimportIsAuthenticatedclassMyBinding(ResourceBinding):permission_classes=(IsAuthenticated,)
最后,要实现自己的权限类,请重写BasePermission的has_permission。
fromchannels_api.permissionsimportBasePermissionclassMyPermission(BasePermission):defhas_permission(self,user,action,pk):ifaction=="CREATE":returnTruereturnFalse