python Django请求工厂中无数据的POST

yyhrrdl8  于 2023-02-11  发布在  Python
关注(0)|答案(3)|浏览(114)

我正在把我的django应用从1.x升级到2.2,当运行单元测试时,我得到一个关于把None作为数据发布的错误。在以前的版本中允许发布None吗?有没有办法通过RequestFactory发布None?
我不想给予空字符串,因为需要验证字段

r = RequestFactory()
rr = r.post("some-url",{"name":"sri", "kd_ratio":None})

错误:

File "/usr/local/lib/python3.7/site-packages/django/test/client.py", line 354, in post
    post_data = self._encode_data(data, content_type)
  File "/usr/local/lib/python3.7/site-packages/django/test/client.py", line 313, in _encode_data
    return encode_multipart(BOUNDARY, data)
  File "/usr/local/lib/python3.7/site-packages/django/test/client.py", line 197, in encode_multipart
    'Cannot encode None as POST data. Did you mean to pass an '
TypeError: Cannot encode None as POST data. Did you mean to pass an empty string or omit the value?
rqcrx0a6

rqcrx0a61#

https://docs.djangoproject.com/en/3.0/topics/testing/tools/#django.test.Client.post
您需要添加content_type="application/json"作为参数,以便能够将None/null作为值发送。
原因是默认的内容类型(multipart/form-data)不支持空值,只支持空字符串,因此提出了这个建议。

cbjzeqam

cbjzeqam2#

我将在这里补充我的一点贡献/观察。
我的view post()方法正在查找request.POST.get(“action”)。因此我不能根据接受的答案设置内容类型,从那时起,这意味着我所有的数据都被移动到request. body。我不打算重写所有这些只是为了测试它们。
因此,我设置了所有的None值,这些值可能出现在通过空字符串发送到视图的测试数据中(这是浏览器实际上无论如何都会发送“None”的值)。在我的例子中,None值看起来是表单中的字段,这些字段由于请求的原因而不存在。

def build_mock_post_data(form, formsets=[]):
    """ builds the k-v pairs that mimics the POST data sent by client, including managment forms & formsets """
    full_post_data = {}
    for formset in formsets:
        prefix = formset.prefix
        fdata = {}
        for i, f in enumerate(formset.initial_forms):
            for key, val in f.initial.items():                   # create the form field's keys
                fdata[f"{prefix}-{i}-{key}"] = str(val)
            fdata[f"{prefix}-{i}-id"] = str(f.fields["id"].initial )                
        fdata[f"{prefix}-TOTAL_FORMS"] = len(formset.initial_forms)
        fdata[f"{prefix}-INITIAL_FORMS"] = len(formset.initial_forms)               # since for test, we always consider the imported fixtures is whatebver will be tested. caller could update that valeur to simulate "new" dets added
        full_post_data.update(**fdata)

    # add main form data
    full_post_data.update(**form.initial)

    # check for None & replace them by empty strings, otherwise issues with django.Client.post(...)
    nones = [k for k,v in full_post_data.items() if v is None]
    for n in nones:
        full_post_data[n] = ""
    return full_post_data

然后在我有需要发送的post数据的测试中:

# prepare post data ...
post_data = build_mock_post_data(form, formsets=[formset])
post_data["action"] = "soumpick"

# TODO: make call
response = self.client.post(reverse('soumission:update_open', args=(ent_soum.id, )), data={**post_data})
r = json.loads(response.content.decode())
log.info(f"Response: {r}")
aamkag61

aamkag613#

希望这能为其他人节省一些时间

这是我在Django 4.1和Django Rest Framework 3.13.1中遇到的问题。
res = self.client.patch("some-url", {"assigned_user": None})
@drew的建议并没有为我解决:
res = self.client.patch("some-url", {"assigned_user": None}, content_type="application/json")
然后我读了文档,明白了这是可行的:
res = self.client.patch("some-url", {"assigned_user": ""})
但我不喜欢它,幸运的是,我发现@Masood Khaari快速通读了问题下面的建议:
res = self.client.patch("some-url", {"assigned_user": None}), format='json')

相关问题