Django中请求工厂(Request Factory)中使用空数据进行POST请求

11

我正在将我的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?

你遇到了什么错误?请在问题中附上堆栈跟踪。 - AKS
StackTrace已附加。 - Sridhar Cr
1
使用format='json'参数:r.post('some-url', {'name': 'sri', 'kd_ratio': None}, format='json') - Masood Khaari
3个回答

22

低估的答案可以拯救生命,哈哈。 - Eduardo Gomes
真相是,Django 4.1 文档在这里: https://docs.djangoproject.com/en/4.1/topics/testing/tools/ - Jeff K

0

我在这里添加我的小贡献/观察。

我认为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

然后在我需要发送帖子数据的测试中:

# 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}")

你有可以分享的代码吗?我已经尝试了被采纳的答案和你的答案,但似乎仍然无法让事情正常运行。 - Seb

0

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

这是我在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')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接