Python Django QueryDict为空,带有request.POST,但填充在request.GET中

Python Django QueryDict为空,带有request.POST,但填充在request.GET中,python,django,twilio,python-2.x,Python,Django,Twilio,Python 2.x,Short version:在django网站上,我可以从请求中获取值。获取但不获取请求。发布以响应Twilio的请求。我怀疑它与csrf有关,但我不确定如何调试这个问题。详情如下 长版本: 我正在帮助一位朋友进行一个项目,我们正在使用Twilio REST API通过短信进行医疗调查。我有一个域和一个非常简单的django在该域上构建的站点,我构建这个站点是为了更好地熟悉django,所以我们正在使用它 我们正在收集对我们调查的短信回复,作为Twilio API的一部分,它会将对我们号码的任何

Short version:在django网站上,我可以从
请求中获取值。获取
但不获取
请求。发布
以响应Twilio的请求。我怀疑它与csrf有关,但我不确定如何调试这个问题。详情如下

长版本: 我正在帮助一位朋友进行一个项目,我们正在使用Twilio REST API通过短信进行医疗调查。我有一个域和一个非常简单的django在该域上构建的站点,我构建这个站点是为了更好地熟悉django,所以我们正在使用它

我们正在收集对我们调查的短信回复,作为Twilio API的一部分,它会将对我们号码的任何回复发送到帐户下指定的url,因此我们的回复目标如下:

...mydomain.com/some_page/another_page/
...mydomain.com/some_page/another_page/?AccountSid=###SOME_LONG_ACCOUNT_SIDE&From=%2BPHONE_NUMBER&Body=bla+BLA+bla+BLA&SmsSid=##MESSAGE_ID_KEY&SmsMessageSid=##MESSAGE_ID_KEY&FromCity=Santa+Cruz&FromState=California...
Twilio请求如下所示:

...mydomain.com/some_page/another_page/
...mydomain.com/some_page/another_page/?AccountSid=###SOME_LONG_ACCOUNT_SIDE&From=%2BPHONE_NUMBER&Body=bla+BLA+bla+BLA&SmsSid=##MESSAGE_ID_KEY&SmsMessageSid=##MESSAGE_ID_KEY&FromCity=Santa+Cruz&FromState=California...

工作代码

我正在测试传入的请求是否包含我们的
AccountSid
(与数据库中的值相比),在我的
views.py
中,对于应用程序,我有如下内容(这是有效的):

非工作代码

如果我登录到我们的Twilio帐户并将请求方法切换到
POST
,然后将所有数据收集切换到
request.POST
,则上述断言语句将失败。进一步的调试显示,我的QueryDict在POST、
POST:{}
下为空,因此没有抓取键值

我认为这可能是因为django下的
POST
需要一个
csrf\u令牌
,但我认为检查AccountSid相当不错,所以我导入了
csrf\u emption
,并用它包装了上述函数:

@csrf_exempt
def twilio_response(request):
    assert request.POST.get('AccountSid', None) == our_account.account_sid
    ## log the incoming request to the database under survey responses...

AssertionError: ...
这不适用于完全相同的请求:QueryDict为空


问题:

1) 我还需要做些什么才能使我的
@csrf\u豁免
工作?另一个问题:这是一种可怕而愚蠢的方式吗?当使用其他公司的API而不是实际的登录用户时,人们通常如何满足这一要求

1a)我可以将其作为
GET
请求保留,而不是将其设置为csrf_豁免,因为我知道它仍在根据我们的帐户sid检查所有传入请求。我应该这样做,还是真的很幼稚


2) 我急切地想知道实现这一点的最佳方法:我是否应该构建一个django表单,然后将请求路由到我的表单,测试有效性并以这种方式清理数据?如果是这样的话,有人能给我一个粗略的轮廓,当没有表单模板时,视图/表单会是什么样子(包括csrf_标记)?

在我的选项中,您是否在settings.py中打开了DEBUG(=True)? 在调试模式下,您可以引发异常(引发异常(“”)),然后您可以在页面中看到环境变量,如url、GET、POST等 或者返回HttpResponse(request.POST.dict()) 查看post变量。
在这里发布Twilio开发者福音派团队的Matt时,使用crsf_豁免是一种正确的方法

1) 用@csrf_emption包装您的twilio_响应函数以删除Django csrf令牌检查是正确的方法。Twilio不生成Django CSRF令牌。相反,还有其他验证来自Twilio的帖子的方法,比如使用X-Twilio-signature头进行签名验证。有关详细信息,请参阅

1a)使用GET请求便于测试和调试,但在生产中应使用POST。根据HTTP规范,GET请求没有正文,因此结果在查询字符串中传递。如果参数太大,例如文本消息的最大长度为1600个字符,则URL中的查询字符串可能超过URL的最大长度,并可能在处理字符串时导致问题

2) Django表单是这个用例的一个好方法,尤其是一个利用现有模型保存响应的ModelForm。例如,您的模型表单可以 如果要将数据保存到TwilioMessage模型,请执行以下操作:

from django.forms import ModelForm
from .models import TwilioMessage


class MessageForm(ModelForm):
    pass

    class Meta:
        model = ReactionEvent
        # include all fields you're saving from the form here
        fields = ['body', 'to', 'from_', 'signature',] 

令人惊叹的。感谢您的详细回复!