为什么Django 1.7告诉我在发送成功的ajax请求后上下文中没有提供csrf_token?

时间:2015-07-06 20:26:00

标签: ajax django csrf django-1.7 django-csrf

当我获得模板并在我的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)

1 个答案:

答案 0 :(得分:0)

在我的django crispy_forms模板中禁用csrf_tag时,我搞砸了。因此,csrf令牌可用作标头,但是render_crispy_form正在尝试呈现csrf令牌,即使它从JsonResponse传回时不存在。

Alasdair的评论指出了我正确的方向。 感谢大家的帮助!