【发布时间】:2015-07-07 06:08:50
【问题描述】:
当我在我的 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)
【问题讨论】:
-
render_crispy_form方法是什么?如果它使用 csrf 令牌呈现表单,那么我希望它将request作为参数。 -
您似乎没有首先显示呈现模板的代码。
-
render_crispy_form 是一种将 django 模型呈现为漂亮的引导 html 的方法。它自动包含一个
{% csrf_token %}标签,但可以禁用它。我已禁用它,因为我在所有帖子请求中都使用了 X-CSRFHeader 标头。 -
编辑问题以包含我的初始模板渲染
标签: ajax django csrf django-1.7 django-csrf