from rest_framework.request import Request
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
# 二次封装request,将原生request作为drf request对象的 _request 属性
self._request = request
def __getattr__(self,item):
return getattr(self._request,item)
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
# 请求对象.data:前端以三种编码方式传入的数据,都可以取出来
# 请求对象.query_params 与Django标准的request.GET相同,只是更换了更正确的名称而已。
from rest_framework.response import Response
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
#data:你要返回的数据,字典
#status:返回的状态码,默认是200,
-from rest_framework import status在这个路径下,它把所有使用到的状态码都定义成了常量
#template_name 渲染的模板名字(自定制模板),不需要了解
#headers:响应头,可以往响应头放东西,就是一个字典
#content_type:响应的编码格式,application/json和text/html;
# 正常返回信息1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
# 返回成功2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
# 重定向3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
# 客户端错误4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
# 客户端错误5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
能够解析的请求编码
默认能够解析:urlencoded、form-data、json
其实通过配置完成:项目没有配置,是在drf内置的配置文件中提前好了
drf也是有俩套的:
一套是项目中得配置(settings.py),一套是默认的配置
drf的配置文件settings.py中有DEFAULT_PARSER_CLASSES(默认的解析类)
-'rest_framework.parsers.JSONParser', 可以解析json格式
-'rest_framework.parsers.FormParser', 可以解析urlencoded格式
-'rest_framework.parsers.MultiPartParser' 可以解析form-data格式
想让我们的接口只能接受json格式
方式一:全局配置---》项目配置文件---》以后所有的接口都遵循这个配置
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
方式二:局部配置
class TestView(APIView):
parser_classes = [JSONParser,FormParser,MultiPartParser]# 注意列表里的类需要先导入, parser_classes这个可以在apiview里看到默认的

总结
解析类的使用顺序:优先用视图类自己的,然后用项目配置文件,最后用内置的
实际项目如何配置:
-基本上都运行JSONParser,FormParser
-如果上传文件只允许MultiPartParser
APIView是REST framework提供的所有视图的基类,继承自Django的View父类。
APIView与View的不同之处
传入到视图方法中的是REST framework的对象,而不是Django的HttpResponse对象;
视图方法可以返回REST framework的Response对象,视图会为响应数据设置符合前端要求的格式;
任何APIView异常都会被捕获到,并且处理成适合的响应信息;
在进行dispatch分发前,会对请求进行身份认证、权限检查、流量控制。(就是之前我对于apiview源码分析出来之后的结果)
由于drf提供了一个顶层的视图类APIView,我们可以通过继承APIView写视图类
但是后期我们可能需要序列化的表比较多,这可能就需要我们重复的书写视图函数的五个接口,这时候我们就可以使用面向对象的继承,封装,使用GenericAPIView进行书写视图函数的5个接口
# APIView
# GenericAPIView-->继承了APIView
-类属性:
queryset = User.objects.all() #queryset传一个queryset对象
serializer_class = UserSerializer # serializer_class传我们需要用自己定义的那个序列化类来序列化数据
-方法:
self.get_object() # 根据pk获取单个数据
self.get_serializer # 获取要使用的序列化类
self.get_queryset() # 获取所有要序列化数据
原来我们基于apiview写的5个接口是这样的:
class UserView(APIView):
def get(self, request):
book_list = User.objects.all()
ser = UserSerializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = UserSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "新增成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
class UserDetailView(APIView):
def get(self, request, pk):
book = User.objects.filter(pk=pk).first()
ser = UserSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = User.objects.filter(pk=pk).first()
ser = UserSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "修改成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
User.objects.filter(pk=pk).delete()
return Response('{'code': 100, 'msg': '删除成功'}')
现在我们基于GenericAPIView写5个接口:
queryset = User.objects.all()
serializer_class = UserSerializer
对于不同的模型表,开设的接口我们只需要该上面两行代码就行
from rest_framework.generics import GenericAPIView
class UserView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request):
book_list = self.get_queryset()
ser = self.get_serializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "新增成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
class UserDetailView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request, pk):
book = self.get_object()
ser = self.get_serializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = self.get_object()
ser = self.get_serializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "修改成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
self.get_queryset().filter(pk=pk).delete()
return Response('{'code': 100, 'msg': '删除成功'}')
进一步优化:基于GenericAPIView和5个视图扩展类写的接口
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# views.py
class Book3View(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset=Book.objects
serializer_class = BookSerializer
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class Book3DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
queryset = Book.objects
serializer_class = BookSerializer
def get(self, request,pk):
return self.retrieve(request,pk)
def put(self, request,pk):
return self.update(request,pk)
def delete(self,request,pk):
return self.destroy(request,pk)
# urls.py
# 使用GenericAPIView+5 个视图扩展类 重写的
path('books3/', views.Book3View.as_view()),
re_path('books3/(?P<pk>\d+)', views.Book3DetailView.as_view()),
再优化:基于GenericAPIView的9个视图子类编写的接口
from rest_framework.generics import ListAPIView,CreateAPIView, RetrieveAPIView,DestroyAPIView,UpdateAPIView
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView
# 正常来讲 Destroy+Update 应该有一个 ,作者没加
class UserView(ListCreateAPIView):
# 配置两个 类属性
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetailView(RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
*1) CreateAPIView*
提供 post 方法
继承自: GenericAPIView、CreateModelMixin
*2)ListAPIView*
提供 get 方法
继承自:GenericAPIView、ListModelMixin
*3)RetireveAPIView*
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
*4)DestroyAPIView*
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
*5)UpdateAPIView*
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
*6)RetrieveUpdateAPIView*
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
*7)RetrieveUpdateDestoryAPIView*
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
*8) ListCreateAPIView*
提供 get、post方法
继承自:GenericAPIView、CreateAPIView、ListAPIView
*9) RetrieveDestroyAPIView*
提供 get、delete方法
继承自:GenericAPIView、RetireveAPIView、DestroyAPIView
再进一步优化:使用ModelViewSet编写5个接口
# views.py
from rest_framework.viewsets import ModelViewSet
class Book5View(ModelViewSet): #5个接口都有,但是路由有点问题
queryset = Book.objects
serializer_class = BookSerializer
# urls.py
# 使用ModelViewSet编写5个接口
path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #当路径匹配,又是get请求,会执行Book5View的list方法
re_path('books5/(?P<pk>\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),
继承ViewSetMixin视图类的视图类,类中的方法可以不必一定写成get、post
# views.py
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前
def get_all_book(self,request):
print("xxxx")
book_list = Book.objects.all()
book_ser = BookSerializer(book_list, many=True)
return Response(book_ser.data)
# urls.py
#继承ViewSetMixin的视图类,路由可以改写成这样
path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),

在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)
在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g
我试图像这样在我的测试用例中执行获取:request.env['CONTENT_TYPE']='application/json'get:index,:application_name=>"Heka"虽然,它失败了:ActionView::MissingTemplate:Missingtemplatealarm_events/indexwith{:handlers=>[:builder,:haml,:erb,:rjs,:rhtml,:rxml],:locale=>[:en,:en],:formats=>[:html]尽管在我的Controller中我有:respond_to:html,
如果使用rspec请求花费的时间太长,我该如何测试行为?我正在考虑使用线程来模拟这个:describe"Test"doit"shouldtimeoutiftherequesttakestoolong"dolambda{thread1=Thread.new{#net::httprequesttogoogle.com}thread2=Thread.new{sleep(xxseconds)}thread1.jointhread2.join}.shouldraise_errorendend我想确保在第一次发出请求后,另一个线程“启动”,在这种情况下只是休眠xx秒。然后我应该期望请求超时,因为执
假设我有:get'/'do$random=Random.rand()response.body=$randomend如果我每秒有数千个请求到达/,$random是否会被共享并“泄漏”到上下文之外,或者它会像getblock的“本地”变量一样?我想如果它是在get'/'do的上下文之外定义的,它确实会被共享,但我想知道在ruby中是否有我不知道的$机制。 最佳答案 ThispartoftheSinatraREADMEaboutscopeisalwayshelpfultoread但是,如果您只需要为请求保留变量,那么我认为我建议使用
运行以下命令时:rvminstall1.9.3我得到以下输出:Error:therequestedURLdoesnotexist:ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-.tar.bz2我已将rvm更新到最新版本并输入rvmreload有什么想法吗? 最佳答案 URL应该是这样的:ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p194.tar.bz2尝试更新您的rvmrvmgethead然后安装1.9.3rvminstall1.9.3