我有一个带有整数字段的模型,用户点击会增加,就像“投票”按钮一样。
该按钮仅显示在详细视图上。要增加投票计数,它会发送一个ajax POST。问题是即使在执行视图之前,django也会返回405(方法不允许)错误。可能导致这种情况的原因是什么?
这是我的代码:
views.py(未执行)
@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代码:
<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'),
)
模板
<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>
答案 0 :(得分:5)
问题不是由url: "../add_support_vote/"
中的相对网址$.ajax
引起的吗?我可以想象,根据您从中触发Ajax调用的页面的位置,可能会调用另一个不允许POST的视图而不是vote_proposal()
。
答案 1 :(得分:1)
不幸的是,奥斯卡这项小型研究没有找到问题,但希望它能帮助您澄清如何修复代码以使其发挥作用。
在主urls.py
中,我创建了两个视图,第一个用于按钮,第二个视图在testap中用于ajax调用处理程序
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}),
)
带有按钮test.html
的模板有点简化以用于测试目的。此外,还添加了csrf hook以防止403 CSRF verification
错误:
<!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>
来自testapp的 urls.py
看起来像
from django.conf.urls.defaults import *
from .views import vote_proposal
urlpatterns = patterns('',
url(r'^add_support_vote/', vote_proposal),
)
和views.py
最大限度地简化了本地化问题
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')
它的确有效。我有200个HTTP响应。
最后一个小建议是使用resolve
来获取从ajax调用处理url的视图函数:
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='')
答案 2 :(得分:0)
我收到 405错误,因为我试图发布到没有POST方法的TemplateView
,如果这有助于任何人。
所以我改为FormView
而不是(有一个POST方法),并且它有效。