How can I post data into test Client post request?
Question:
I’m writing a test to see if form data is validating on post request trying to create a Post object.
tests.py
def setUp(self):
user = User.objects.create_user(email='[email protected]', password='test', name='test')
self.user = User.objects.get(email='[email protected]')
self.client.login(email=user.email, password=user.password)
@tag('fast')
def test_index(self):
client = Client()
response = client.post(reverse('index'), data={'user': self.user, 'body': 'Test'}, follow=True)
print(response, self.user)
self.assertTrue(Post.objects.filter(body='Test').exists())
but the test fails with message False is not true
implying that the object with body "Test"
was not created. I already tried encoding data with urlencode but it did not help.
Here is what print statement shows: <TemplateResponse status_code=200, "text/html; charset=utf-8"> test
views.py
def index(request):
posts = Post.objects.all()
if request.method == 'POST':
form = NewPostForm(request.POST, request.FILES)
if form.is_valid():
new_post = form.save(commit=False)
new_post.user = user
new_post.save()
return redirect('index')
else:
form = NewPostForm(instance=None)
context = {
'form': form,
'posts': posts
}
return render(request, 'index.html', context=context)
Maybe the user isn’t being serialized correctly but when I remove it from data attribute (which would mean that the current user should be assigned to Post object) I get basically the same result.
Answers:
You could try adding Content-Type:application/json
in the header of you request
as in the error message above it is showing the the request you are sending is in the plain text
In the end I decided to just test it for valid response and leave the data validation part to the form validation test, here’s what it looks like now:
def test_index(self):
client = Client()
get_response = client.get('/home/', {}, True)
post_response = client.post(reverse('index'), data={'body': 'Test'}, follow=True)
self.assertEqual(get_response.status_code, 200)
self.assertEqual(post_response.status_code, 200)
If anyone has any suggestions I would love to see them though because my particaular qestion problem still exists.
new_post.user = user
should probably be new_post.user = request.user
Then you don’t even need to pass user in the POST and it’ll just auto grab it from the request
The 200 status isn’t very helpful in this situation because no matter what (create an object or fail to create one) it’ll redirect to index
So my guess would be the form is failing the validation.
There’s not enough info for me to give a direct Answer, but here’s some steps to debug:
- Place a
print('Validation:', form.errors.as_data())
below+tabbed-left of the redirect('index')
- This will let you know if the form is failing it’s validation
- Place a
print('POST:', request.POST)
below+tabbed-right of the request.method == 'POST':
- This will let you see if the data is actually getting there in the first place
- Re-Run the Tests
- Validation Error?:
- maybe it’s missing a field.
- maybe user is a required field and thus can’t pass validation without it.
- Allow user to be blank and/or null + set User in the
.is_valid()
(like you’re doing)
- Post Data Empty?: there’s a direction, why?
I just ran into a similar issue using Django 3.2.4, my data wasn’t getting there
I was using:
- attempt 1:
client.post('post/url', data=formdatadict, content_type='application/json')
- attempt 2:
client.post('post/url', data=json.dumps(formdatadict), content_type='application/json')
- My Solution:
client.post('post/url', data=formdatadict)
Note: I’m using self.client.post()
but c = Client()
+ c.post()
would work
Sooo hopefully this helps someone with their debugging
(especially because tests take so long to run)
I’m writing a test to see if form data is validating on post request trying to create a Post object.
tests.py
def setUp(self):
user = User.objects.create_user(email='[email protected]', password='test', name='test')
self.user = User.objects.get(email='[email protected]')
self.client.login(email=user.email, password=user.password)
@tag('fast')
def test_index(self):
client = Client()
response = client.post(reverse('index'), data={'user': self.user, 'body': 'Test'}, follow=True)
print(response, self.user)
self.assertTrue(Post.objects.filter(body='Test').exists())
but the test fails with message False is not true
implying that the object with body "Test"
was not created. I already tried encoding data with urlencode but it did not help.
Here is what print statement shows: <TemplateResponse status_code=200, "text/html; charset=utf-8"> test
views.py
def index(request):
posts = Post.objects.all()
if request.method == 'POST':
form = NewPostForm(request.POST, request.FILES)
if form.is_valid():
new_post = form.save(commit=False)
new_post.user = user
new_post.save()
return redirect('index')
else:
form = NewPostForm(instance=None)
context = {
'form': form,
'posts': posts
}
return render(request, 'index.html', context=context)
Maybe the user isn’t being serialized correctly but when I remove it from data attribute (which would mean that the current user should be assigned to Post object) I get basically the same result.
You could try adding Content-Type:application/json
in the header of you request
as in the error message above it is showing the the request you are sending is in the plain text
In the end I decided to just test it for valid response and leave the data validation part to the form validation test, here’s what it looks like now:
def test_index(self):
client = Client()
get_response = client.get('/home/', {}, True)
post_response = client.post(reverse('index'), data={'body': 'Test'}, follow=True)
self.assertEqual(get_response.status_code, 200)
self.assertEqual(post_response.status_code, 200)
If anyone has any suggestions I would love to see them though because my particaular qestion problem still exists.
new_post.user = user
should probably be new_post.user = request.user
Then you don’t even need to pass user in the POST and it’ll just auto grab it from the request
The 200 status isn’t very helpful in this situation because no matter what (create an object or fail to create one) it’ll redirect to index
So my guess would be the form is failing the validation.
There’s not enough info for me to give a direct Answer, but here’s some steps to debug:
- Place a
print('Validation:', form.errors.as_data())
below+tabbed-left of theredirect('index')
- This will let you know if the form is failing it’s validation
- Place a
print('POST:', request.POST)
below+tabbed-right of therequest.method == 'POST':
- This will let you see if the data is actually getting there in the first place
- Re-Run the Tests
- Validation Error?:
- maybe it’s missing a field.
- maybe user is a required field and thus can’t pass validation without it.
- Allow user to be blank and/or null + set User in the
.is_valid()
(like you’re doing)
- Allow user to be blank and/or null + set User in the
- Post Data Empty?: there’s a direction, why?
- Validation Error?:
I just ran into a similar issue using Django 3.2.4, my data wasn’t getting there
I was using:
- attempt 1:
client.post('post/url', data=formdatadict, content_type='application/json')
- attempt 2:
client.post('post/url', data=json.dumps(formdatadict), content_type='application/json')
- My Solution:
client.post('post/url', data=formdatadict)
Note: I’m usingself.client.post()
butc = Client()
+c.post()
would work
Sooo hopefully this helps someone with their debugging
(especially because tests take so long to run)