从Django中的表单发送DELETE请求

时间:2015-05-26 14:45:50

标签: jquery django

我正在尝试从Django中的表单发送DELETE请求,从jQuery获取帮助,请参阅下面的链接;

https://baxeico.wordpress.com/2014/06/25/put-and-delete-http-requests-with-django-and-jquery/

我所拥有的是以下脚本;

<script src="jquery-1.11.3.js"></script>

<script>
  $(document).ready(function(){
    $.ajax({
      id : 'delete',
      headers : {'X_METHODOVERRIDE': 'DELETE'}
    });
  });
</script>

(我打算)按照以下表格行事;

<form method="post" id="delete" name="delete" action="">
  {% csrf_token %}
  <input type="submit" value="Delete" />
</form>

以下中间件;

from django.http import QueryDict

class HttpPostTunnelingMiddleware(object):
    def process_request(self, request):
        if request.META.has_key('HTTP_X_METHODOVERRIDE'):
            http_method = request.META['HTTP_X_METHODOVERRIDE']
            if http_method.lower() == 'put':
                request.method  = 'PUT'
                request.META['REQUEST_METHOD'] = 'PUT'
                request.PUT = QueryDict(request.body)
            if http_method.lower() == 'delete':
                request.method  = 'DELETE'
                request.META['REQUEST_METHOD'] = 'DELETE'
                request.DELETE = QueryDict(request.body)
        return None        

我已将它添加到settings.py中的MIDDLEWARE_CLASSES列表中;

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'stationrunner.middleware.HttpPostTunnelingMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

这是第3条,在考虑@Daniel Roseman的CsrfViewMiddleware之前。

最后在我的基于类的视图中我有删除方法删除相应的对象;

class StationHome(View):
    .
    .
    .
    def post(self,request, pk):
        station = Station.objects.get(pk=pk)
        form = StationForm(request.POST, instance=station)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse("home_station",
                                                kwargs={'pk':pk},
                                            )
                                    )
        else:
            return HttpResponse("Form Invalid!")

    def delete(self, request, pk):
        Station.objects.get(pk=pk).delete()
        return HttpResponseRedirect(
            reverse("list_create_station")                      
            )
    .
    .

我希望中间件和脚本向视图发送DELETE请求,但事情并没有发生。 POST方法本身正在发送。 Django找到了一个无效的表格并给我回复; “表格无效!” (else: return HttpResponse("Form Invalid!"

更新

我已将脚本更新为:

<script>
  $(document).ready(function(){
    $('#delete').submit.function(e){
      e.preventDefault();
      var station_id = {{ station.id }}
      $.ajax({
        type: 'POST',
        url: '/station/' + station_id,
        headers: {'X_METHODOVERRIDE': 'DELETE'}
      });
    });
  });
</script>

我将对象作为station传递给模板,我在脚本(var station_id = {{ station.id }})中使用了Django模板语言,灵感来自https://stackoverflow.com/a/6008968/4672736

结果是一样的:/

更新

调试js发现浏览器没有找到jQuery文件。现在正确配置了静态文件,并且在jquery.cookie.js的帮助下设置了csrf保护我在我的模板中有以下代码;

<script src="{% static "stationrunner/jquery-1.11.3.js" %}"></script>
<script src="{% static "stationrunner/jquery.cookie.js" %}"></script>

<script>
  $(document).ready(function(){
    var csrftoken = $.cookie('csrftoken');
    function csrfSafeMethod(method) {
      // these HTTP methods don't require CSRF protection
      return(/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if(!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
    $('#delete').submit(function(e){
      e.preventDefault();
      $.ajax({
        type: 'POST',
        url: '{% url 'home_station' station.id %}',
        headers: {'X_METHODOVERRIDE': 'DELETE'}
      });
    });
  });
</script>

现在我的前端没有错误但是还没有成功。提交表单会获得200响应而不是302

这是否需要AJAX请求?

似乎请求尚未作为删除请求传递给视图。

我尝试将success: function(){alert('Object deleted!')}添加到$.ajax,然后弹出警报。

更新

最后的障碍是我必须在传递的自定义标头中使用短划线而不是下划线。我将headers: { 'X_METHODOVERRIDE': 'DELETE' }更改为headers: { 'X-METHODOVERRIDE': 'DELETE' }。这些字母也不必用大写字母传递。无论如何,Django会将它们转换为大写字母。因此x-methodoverridex-MeThODoveRrIDE也很好。我不知道为什么破灭而不是下划线。我想通了,因为传递的其他标题都带有破折号,而不是下划线。

早些时候,中间件没有找到密钥HTTP_X_METHODOVERRIDE。现在它确实和我的视图获得删除请求:)

2 个答案:

答案 0 :(得分:3)

问题在于你的javascript代码。您将表单作为常规POST请求提交,而不是使用$ .ajax javascript代码。

您应该在单独的脚本标记中包含jquery,如下所示:

<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>

然后在另一个脚本标记中放置代码:

<script>
    $('#delete').submit(function(e) {
        // do NOT submit the form as a regular POST request
        e.preventDefault();
        var object_to_delete_id = $('#object_to_delete_id').val();
        $.ajax({
            type: 'POST',
            url: '/your-view-url/' + object_to_delete_id,
            success: function() {
                alert('Object deleted!')
            },
            headers: { 'X_METHODOVERRIDE': 'DELETE' }
        });
    });
<script>

我假设您在表单字段中拥有要删除的对象的ID,如下所示:

<form method="post" id="delete" name="delete" action="">
  {% csrf_token %}
  <input type="text" id="object_to_delete_id" />
  <input type="submit" value="Delete" />
</form>

请注意Ajax调用上的Django CSRF保护,您应该在请求中编写一些javascript来设置CSRF cookie值,如Django documentation中所述。

同样将HttpResponseRedirect返回到Ajax调用并没有多大意义,因为浏览器不会像常规POST请求那样重定向到该页面。

在开始研究像这样的更复杂的例子之前,我建议更多地研究jquery和Ajax请求是如何工作的。 ;)

答案 1 :(得分:0)

这可能是您的中间件的排序。收到请求后,将按照在设置中指定的顺序处理中间件。在您的情况下,这意味着首先运行CSRF中间件,看到请求是没有CSRF令牌的POST,并引发错误。

尝试在CsrfViewMiddleware之前移动您的HttpPostTunnelingMiddleware。