当我获得模板并在我的Django 1.7应用程序中呈现表单时,我在Python服务器控制台上没有错误。我可以使用Django文档中提供的X-CSRFHeader建议使用AJAX提交表单,并且请求成功并且不会抛出403禁止。我甚至可以使用不同的信息(这是期望的行为)再次提交此表格,并且仍然取得了成功。
我担心的是,在第一个POST请求之后,控制台显示:
UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.'
第一次呈现模板时,它使用render(request, 'appname/index.html', context)
呈现它,我理解应该包含RenderContext()
在更有效的方法中提供的相同信息。
有没有人知道可能出现的问题?
我的ajax代码:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin 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(){
var csrftoken = $.cookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// Define ajax submit function
$('.tab-pane form').submit(function (event){
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
data: new FormData($('.tab-pane.active form').get(0)),
dataType: "json",
processData: false,
contentType: false,
success: function(data) {
// Re-enable submit button
$(".submit-btn").removeClass("disabled");
$(".cancel-btn").removeClass("disabled");
// Show errors or clean and reset form
$('.tab-pane.active form div:first').replaceWith(data['form_html']);
if (data['success']) {
// Close modal
$('#incidentForm').modal('hide');
// Add point to map
var point = geojsonMarker(JSON.parse(data['point']), data['point_type'])
point.bindPopup(getPopup(point.getLayers()[0]));
incidentData.addLayer(point);
// Pan to point
map.setView(point.getBounds().getCenter(), 18, {'animate': true});
setTimeout(function(){
point.openPopup();
}, 300);
// Print success or failure message
var message = "<strong>" + '{% trans "Thank you!" %}' + "</strong><br>" + '{% trans "Your incident marker was successfully added." %}';
showMessage(message);
}
}
});
event.preventDefault();
});
})
我的查看方法如下:
@require_POST
def postTheft(request):
return postPoint(request, TheftForm)
def postPoint(request, Form):
"""Submit a user point submission to the database. Normalize geometry and activate push notifications."""
form = Form(request.POST)
form.data = form.data.copy()
# Convert coords to valid geometry
try:
form.data['geom'] = normalizeGeometry(form.data['geom'])
except(ValueError):
messages.error(request, '<strong>' + _('Error') + '</strong><br>' + _('No point was selected for this type of report.'))
# Validate and submit to db
if form.is_valid():
point = form.save()
# Errors with push notifications should not affect reporting
if not settings.DEBUG:
try: pushNotification.pushNotification(point)
except: pass
return JsonResponse({
'success': True,
'point': GeoJSONSerializer().serialize([point,]),
'point_type': point.p_type,
'form_html': render_crispy_form(Form())
})
else:
logger.debug("Form not valid")
# Else: error occurred
form.data['geom'] = form.data['geom'].json
form_html = render_crispy_form(form)
return JsonResponse({'success': False, 'form_html': form_html})
呈现初始模板的代码:
def index(request, lat=None, lng=None, zoom=None):
incidents = Incident.objects.select_related('point').all()
context = {
# Model data used by map
'collisions': incidents.filter(p_type__exact="collision"),
'nearmisses': incidents.filter(p_type__exact="nearmiss"),
'hazards': Hazard.objects.select_related('point').all(),
'thefts': Theft.objects.select_related('point').all(),
"geofences": AlertArea.objects.filter(user=request.user.id),
# Form data used by map
"incidentForm": IncidentForm(),
"geofenceForm": GeofenceForm(),
"hazardForm": HazardForm(),
"theftForm": TheftForm(),
"editForm": EditForm()
}
# Add zoom and center data if present
if not None in [lat, lng, zoom]:
context['lat']= float(lat)
context['lng']= float(lng)
context['zoom']= int(zoom)
return render(request, 'mapApp/index.html', context)
答案 0 :(得分:0)
在我的django crispy_forms模板中禁用csrf_tag时,我搞砸了。因此,csrf令牌可用作标头,但是render_crispy_form正在尝试呈现csrf令牌,即使它从JsonResponse传回时不存在。
Alasdair的评论指出了我正确的方向。 感谢大家的帮助!