405 error on django ajax POST

三世轮回 提交于 2019-12-12 15:05:07

问题


I have a model with a integer field wich will increment on user click, like a "vote this" button.

The button only shows on the detail view. To increment the vote count it sends an ajax POST. The problem is that django returns a 405 (method not allowed) error even before executing the view. What can be causing this?

Here is my code:

views.py (doesn't get executed)

@require_POST
def vote_proposal(request, space_name):

    """
    Increment support votes for the proposal in 1.
    """
    prop = get_object_or_404(Proposal, pk=request.POST['propid'])
    proposal_form = VoteProposal(request.POST or None, instance=prop)

    if request.method == "POST" and request.is_ajax:
        if proposal_form.is_valid():
            vote = proposal_form.cleaned_data['propid']
            vote.support_votes += 1
            vote.save()
            msg = "The vote has been saved."
        else:
            msg = "The vote didn't pass validation."
    else:
        msg = "An error has ocurred."

    return HttpResponse(msg)

jQuery code:

<script type="text/javascript">
    function upvote(proposal) {
        var request = $.ajax({
            type: "POST",
            url: "../add_support_vote/",
            data: { propid: proposal }
        });

        request.done(function(msg) {
            var cur_votes = $("#votes span").html();
            var votes = cur_votes += 1;
            $("#votes span").html().fadeOut(1000, function(){
                $("#votes span").html(votes).fadeIn();
            });
        });

        request.fail(function(jqXHR, textStatus) {
            $("#jsnotify").notify("create", {
                title:"Couldn't vote the proposal",
                text:"There has been an error." + textStatus,
                icon:"alert.png"
            });
        })
     }
</script>

urls.py

urlpatterns = patterns('e_cidadania.apps.proposals.views',

    url(r'^$', ListProposals.as_view(), name='list-proposals'),

    url(r'^add/$', 'add_proposal', name='add-proposal'),

    url(r'^(?P<prop_id>\w+)/edit/$', 'edit_proposal', name='edit-proposal'),

    url(r'^(?P<prop_id>\w+)/delete/$', DeleteProposal.as_view(), name='delete-proposal'),

    url(r'^(?P<prop_id>\w+)/', ViewProposal.as_view(), name='view-proposal'),

    url(r'^add_support_vote/', 'vote_proposal'),

)

Template

<div id="votes">
    <span style="font-size:30px;text-align:center;">
        {{ proposal.support_votes }}
    </span><br/>
    <button onclick="upvote({{ proposal.id }})" class="btn small">{% trans "support" %}</button>
</div>

回答1:


Couldn't the problem be caused by the relative URL url: "../add_support_vote/" in $.ajax? I can imagine that another view that doesn't allow POST might be called instead of vote_proposal() depending on the location of the page from which you trigger the Ajax call.




回答2:


Oscar unfortunately this small research didn't found the issue, but hope it will help you to clarify how to fix your code to get it work.

In main urls.py I've created two views first one for the button, the second one in testap for ajax call handler

from django.conf import settings
from django.conf.urls.defaults import patterns, include, url    
from django.views.generic.simple import direct_to_template

urlpatterns = patterns(''    
    url(r'^$', direct_to_template , {'template':'test.html'}),
    url(r'^test/', include('testapp.urls')),
)    

if settings.DEBUG:
    urlpatterns += patterns(
        '',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
)

My template with button test.html a bit simplified for test purposes. Also csrf hook has been added to prevent 403 CSRF verification error:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="{{ MEDIA_URL }}js/jquery-1.6.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        function sameOrigin(url) {
            // url could be relative or scheme relative or absolute
            var host = document.location.host; // host + port
            var protocol = document.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        }
        function safeMethod(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }

        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    });

       function upvote(proposal) {
           var request = $.ajax({
               type: "POST",
               url: "../test/add_support_vote/",
               data: { propid: proposal }
           });

           request.done(function(msg) {
               var cur_votes = $("#votes span").html();
               var votes = cur_votes += 1;
               $("#votes span").html().fadeOut(1000, function(){
                   $("#votes span").html(votes).fadeIn();
               });
           });

           request.fail(function(jqXHR, textStatus) {
               $("#jsnotify").notify("create", {
                   title:"Couldn't vote the proposal",
                   text:"There has been an error." + textStatus,
                   icon:"alert.png"
               });
           })
        }
   </script>
</head>
<body>
<div id="votes">
    <button onclick="upvote(1)" class="btn small">support</button>
</div>
</body>
</html>

urls.py from testapp looks like

from django.conf.urls.defaults import *
from .views import vote_proposal

urlpatterns = patterns('',
    url(r'^add_support_vote/', vote_proposal),

)

and views.py which maximally simplified to localize the issue

from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_POST

@require_POST
def vote_proposal(request):
    return HttpResponse('ok')

And it's works. I've got 200 HTTP response.


Also final small suggestion to use resolve to get view function which handle url from ajax call:

from django.core.urlresolvers import resolve
resolve('/test/add_support_vote/')
# returns ResolverMatch(func=<function vote_proposal at 0x2b17230>, args=(), kwargs={}, url_name='testapp.views.vote_proposal', app_name='None', namespace='')



回答3:


I was getting a 405 error because I was trying to POST to a TemplateView which doesn't have a POST method, if that helps anyone.

So I changed it to a FormView instead (which has a POST method), and it worked.



来源:https://stackoverflow.com/questions/7819206/405-error-on-django-ajax-post

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!