handle OPTIONS request with django's built in server

McFarlane picture McFarlane · Aug 12, 2013 · Viewed 11.9k times · Source

I am trying to make OPTIONS requests work with django but I am currently only getting 405. An answer I got here was that the server does not handle the OPTIONS request.

This is the View that handles the request:

from django.views.generic import View
from piston.utils import coerce_put_post

class TheView(View):

    @staticmethod
    def find_stuff(params):
        ...

    @staticmethod
    def do_stuff(params):
        ...

    @staticmethod
    def do_other_stuff(params):
        ...

    @staticmethod
    def delete_some_stuff(params):
        ...

    @method_decorator(staff_member_required)
    def get(self, request, id):
        result = self.find_stuff(id)
        return JsonResponse(result)

    @method_decorator(staff_member_required)
    def post(self, request):
        result = self.do_stuff(request.POST)
        return JsonResponse(result)

    @method_decorator(staff_member_required)
    def put(self, request, id):
        coerce_put_post(request)
        result = self.do_other_stuff(id,request.PUT)
        return JsonResponse(result)

    @method_decorator(staff_member_required)
    def delete(self, request,id):
        result = self.delete_some_stuff(id)
        return JsonResponse(result)

I am sending the request with jQuery's $.ajax(). This is the network log captured by chrome's dev tool:

  • Request URL : http://localhost
  • Request Method : OPTIONS
  • Status Code : 405 METHOD NOT ALLOWED

Request Headers

  • Accept : /
  • Accept-Encoding : gzip,deflate,sdch
  • Accept-Language : de,en-US;q=0.8,en;q=0.6
  • Access-Control-Request-Headers : accept, origin, content-type
  • Access-Control-Request-Method : PUT
  • Cache-Control : no-cache
  • Connection : keep-alive
  • Host : foo
  • Origin : http://localhost
  • Pragma : no-cache
  • Referer : http://localhost/bar
  • User-Agent : Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36

Response Headers

  • Access-Control-Allow-Credentials : true
  • Access-Control-Allow-Headers : Content-Type, Pragma, Cache-Control
  • Access-Control-Allow-Methods : POST,GET,OPTIONS,PUT,DELETE
  • Access-Control-Allow-Origin : http://localhost
  • Allow : post,get,options,put,delete
  • Content-Type : text/html; charset=utf-8
  • Date : Fri, 09 Aug 2013 09:39:41 GMT
  • Server : WSGIServer/0.1 Python/2.7.4

So how can I get the django server to handle it?

Answer

Derek Kwok picture Derek Kwok · Aug 12, 2013

I would suspect that OPTIONS request is returning a 405 error because an options handler hasn't been defined in your view class. Note that Django does not provide a default options handler.

Here is the code (django source code) that is responsible for calling the appropriate methods on your class:

# snippet from  django.views.generic.base.View

http_method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace']

def dispatch(self, request, *args, **kwargs):
    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

options is one of the default http method that can be handled in Django view. If the options handler hasn't been defined, the dispatch method returns a 405 error.


Here is an example of options method

class TheView(View):

    self.allowed_methods = ['get', 'post', 'put', 'delete', 'options']
    def options(self, request, id):
        response = HttpResponse()
        response['allow'] = ','.join([self.allowed_methods])
        return response