22👍
https://docs.djangoproject.com/en/4.2/topics/testing/tools/#django.test.Client.post
You need to add content_type="application/json"
as an argument to be able to send None/null as a value.
The reason is that the default content type (multipart/form-data) doesn’t support null values, only empty strings, hence the suggestion.
1👍
Hopefully this saves some time for someone else
This was my problem in Django 4.1 and Django Rest Framework 3.13.1.
res = self.client.patch("some-url", {"assigned_user": None})
@drew’s suggestion did not solve it for me:
res = self.client.patch("some-url", {"assigned_user": None}, content_type="application/json")
Then I read the docs and understood that this works:
res = self.client.patch("some-url", {"assigned_user": ""})
But I didn’t like it and luckily I found @Masood Khaari quickly-overread suggestion below the question:
res = self.client.patch("some-url", {"assigned_user": None}), format='json')
0👍
I’ll add my little contribution/observation here.
My view post() method is looking for request.POST.get("action"). Thus I couldn’t set the content-type as per the accepted answer, since then that means that all my data is moved to the request.body. I’m not going to re-write all those just so I can test them.
Thus instead, I have set all None value that may be present in the test data sent to the views by an empty string (which is what the browser would actually send a "None" as anyways). In my case, the None value appeared to be fields in the Form that were not present for whatever reason the request.
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
Then in the tests where I have post data I need to sent:
# 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}")
- Django disable editing (but allow adding) in TabularInline view
- How do I update an object's members using a dict?