我在以下重复步骤下得到403:
结果:403错误。这很可能是预期的行为,但我正在寻找一种更优雅的方式来处理这个问题。是否有一种很好的方法来捕获这个并重新提交表单作为登录用户?
答案 0 :(得分:3)
我已经在许多框架的上下文中看到了这个问题,唯一优雅的解决方案是JavaScript。
使用JavaScript,您可以将输入值存储在localStorage
中。然后在成功的表单提交事件中,清除这些值。如果表单加载了localStorage
中存在的那些值(表单提交返回403,并且用户返回到表单页面),则自动使用值填充表单。
实施起来并不复杂,只需要做更多的工作。我相信有基于这个想法的JS库......
为所有表单元素指定一个类名。在示例中,我将使用store-data
。如果您在django中定义表单,则可以在forms.Widget.attrs
中设置,如果您编写自己的html,则可以在输入元素上使用class
属性设置。
在提交时,将名为formData
的项目添加到localStorage
。 formData
是一个JS对象映射表单字段元素id,其中classname从上面到元素值。
如果表单已提交并处理为有效,请在重定向页面上使用formData
从localStorage
移除localStorage.removeItem()
。
加载表单页面时(这是用户在403之后返回表单的位置),如果formData
中存在localStorage
,则将值加载到表单字段中。
以下是实施此示例的示例:
<form name="myForm" action="{% url 'myapp:form_submit' %}" onsubmit="return storeData()">
<label>Name: </label>
<input type="text" class="store-data" id="inputName" />
<label>Description: </label>
<textarea class="store-data" id="textareaDescription"></textarea>
<input type="submit" />
</form>
<script>
function storeData() {
var elements = document.getElementsByClassName("store-data");
var formData = {};
// store element ids and values in formData obj
for (var i = 0; i < elements.length; i++) {
formData[elements[i].id] = elements[i].value;
}
// store formData to localStorage as string
localStorage.setItem('formData', JSON.stringify(formData));
}
// if the localStorage item has already been set, then the user tried to submit and failed
if (localStorage.getItem('formData')) {
formData = JSON.parse(localStorage.getItem('formData'))
// set all the form elements to the values that were stored when the user tried to submit
for (var key in formData) {
document.getElementById(key).value = formData[key];
}
}
</script>
在重定向的成功页面上,请务必删除formData
项。否则,只要用户返回表单,值就会被加载到字段中。 (我想这可能是一种理想的行为,但我对此表示怀疑。)
<script>
localStorage.removeItem('formData');
</script>
答案 1 :(得分:2)
嗯,是的,这是预期的行为。登录时,会生成新的csrf_token。当您导航回带有验证错误的页面时,它仍然包含<input type="hidden" name="csrfmiddlewaretoken" value="old_token" />
中的旧csrf_token。因此,您使用无效的csrf_token提交表单并获得403错误。
我可以为你推荐两种选择(我不喜欢它们)
在登录时禁用新的csrf_token生成。只需在request.META['CSRF_COOKIE_USED'] = False
之后将login(request, user)
放在您的登录视图中。
为您的单个视图停用csrf保护via decorator,或从settings.py中删除csrf middleware全局。