Reputation: 2902
I'd like to build a request for testing middleware, but I don't want POST requests to always assume I'm sending form data. Is there a way to set request.body
on a request generated from django.test.RequestFactory
?
I.e., I'd like to do something like:
from django.test import RequestFactory
import json
factory = RequestFactory(content_type='application/json')
data = {'message':'A test message'}
body = json.dumps(data)
request = factory.post('/a/test/path/', body)
# And have request.body be the encoded version of `body`
The code above will fail the test because my middleware needs the data to be passed as the document in request.body
not as form data in request.POST
. However, RequestFactory
always sends the data as form data.
I can do this with django.test.Client
:
from django.test import Client
import json
client = Client()
data = {'message':'A test message'}
body = json.dumps(data)
response = client.post('/a/test/path/', body, content_type='application/json')
I'd like to do the same thing with django.test.RequestFactory
.
Upvotes: 10
Views: 10192
Reputation: 49
In later version of Django (tested on 4.0) this is no longer an issue. On the other hand, to pass data to request.POST
might be.
In default, when passing content-type
to a RequestFactory, data goes into request.body
and when you don't, data goes into request.POST
.
request_factory = RequestFactory()
# provide content-type
request = request_factory.post(f'url', data={'foo': 'bar'}, content_type="application/json")
print(request.body) # b'{"foo": "bar"}'
# don't provide content type
request = request_factory.post(f'url', data={'foo': 'bar'})
print(request.POST) # <QueryDict: {'foo': ['bar']}>
Upvotes: 1
Reputation: 223
Here's what worked for me in Django 4.1:
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase, RequestFactory
from customauth import views
class RegistrationViewTest(TestCase):
def setUp(self):
self.factory = RequestFactory()
def test_post_request_creates_new_user(self):
data = {
'email': '[email protected]',
'screen_name': 'new_user',
'password1': 'new_user_password',
'password2': 'new_user_password',
}
request = self.factory.post('/any/path/will/do/', data )
middleware = SessionMiddleware(request)
middleware.process_request(request)
request.session.save()
response = views.registration_view(request)
self.assertEqual(response.status_code, 302)
# ok
This test passes. The form was successfully processed in views.registration_view
.
Note:
content_type='application/json'
in the call to self.factory.post
(as the accepted answer suggests), request.POST
had no content in the view. Without that, it worked. I don't know why but would be happy to learn.SessionMiddleware
to request
.Upvotes: 1
Reputation: 166
I've tried Jay's solution and didn't work, but after some reseach, this did (Django 2.1.2)
factory = RequestFactory()
request = factory.post('/post/url/')
request.data = {'id': 1}
Upvotes: 2
Reputation: 599450
RequestFactory has built-in support for JSON payloads. You don't need to dump your data first. But you should be passing the content-type to post
, not to the instantiation.
factory = RequestFactory()
data = {'message':'A test message'}
request = factory.post('/a/test/path/', data, content_type='application/json')
Upvotes: 14