【发布时间】:2020-06-04 22:05:11
【问题描述】:
我有一个邮件列表系统,用户可以在其中单击链接取消订阅。此链接在 GET 参数中包含用户的电子邮件,并且它指向的页面包含请求反馈的简短表单。此反馈需要指向提交它的用户的电子邮件。
我尝试实现的方法是:
- 从 GET 参数中获取电子邮件
- 将其作为
initial值放在反馈表单的隐藏字段中 - 在发送表单时从表单数据中检索它
问题是,如果这个隐藏字段没有被禁用,用户可以干预它的值并伪装自己的身份,甚至声称反馈来自另一个用户。但是,如果我将该字段设置为禁用,则 request.POST 字典根本不包含该字段。
我还尝试启用该字段并检查它在form.changed_data 中的存在,但它似乎总是存在,即使它的值没有改变。
这是表单类:
class UnsubscribeForm(forms.Form):
reason = forms.ChoiceField(choices=UnsubscribeFeedback.Reasons.choices)
comment = forms.CharField(widget=forms.Textarea, required=False)
user_email = forms.CharField(widget=forms.HiddenInput, required=False, disabled=False)
当方法为 GET 时,这就是我在视图中填充 user_email 的方式:
email = request.GET.get("email", "")
# ...
context["form"] = UnsubscribeForm(initial={"user_email": email})
请注意,我还尝试在此行之后手动禁用该字段,以及在表单的 init 方法中。结果是一样的:如果该字段被禁用,则该值不会被传递。
设置初始值后,我对其进行了 print() 以确保设置正确,并且确实如此。我还检查了页面的源代码,它正确显示了该值。
当接收到数据绑定表单时,这就是我在视图的 POST 部分检查值的方式:
form = UnsubscribeForm(request.POST)
if form.is_valid(): # This passes whether I change the value or not.
if "user_email" in form.changed_data: # This too passes whether I change the value or not.
print("Changed!")
email = form.cleaned_data["user_email"] # This is "" if user_email is disabled, else the correct value.
我不知道为什么当该字段被禁用时我设置的初始值会被忽略。据我所知,无论任何更改,禁用的字段都会传递初始值,但这里根本没有传递初始值。正如我上面所概述的,我不能让用户可以编辑这个字段,即使它是隐藏的。
Django 是 3.0.3 版,如果这很重要的话。
有什么解决办法吗?这是一个错误吗?
【问题讨论】:
-
您是否需要表单中的电子邮件字段?使用
request.user.email在你的视图中获取用户的电子邮件不是更省钱吗? -
用户没有登录网站,没有登录系统,所以请求本身不包含相关信息。
-
我明白了。仅当您向表单实例提供初始数据时检查更改的数据才有效,例如
form = UnsubscribeForm(request.POST, initial={...})。因此,您需要帖子视图中的电子邮件。但是你不需要它的形式。简而言之:恕我直言,您的方法行不通。 -
如果我可以通过禁用输入的初始数据传递数据,我不需要检查更改的数据——这是我最初的方法。根本就没有办法检索这些数据吗?如果是这样,如果隐藏字段只能在用户也可以干预的情况下使用,那么隐藏字段有什么用?
-
不确定,但是否有可能添加基于电子邮件的哈希令牌和要检查的密钥?
标签: django post django-forms hidden-field disabled-input