I'm using Django Rest Framework for my API. I'm testing account creation
using my API.
{{{
from django.urls import reverse
from django.contrib.auth import get_user_model
from rest_framework import status
from rest_framework.request import Request
from rest_framework.test import APITestCase, APIClient, APIRequestFactory
from rest_framework.authtoken.models import Token
class AccountCreationTests(APITestCase):
"""
This is the account creation tests for the /api/users endpoint on
angular
"""
fixtures = ['user_dev', 'order_dev']
def setUp(self):
self.client = APIClient()
self.factory = APIRequestFactory()
def test_create_account_fails(self):
"""
Ensure we can't create a new account object without required keys
on angular
"""
url = reverse('user-list')
data = {'email': 'te...@example.com'}
# fails because of required fields
response = self.client.post(url, data, format='json')
print("\n\ntest_create_account_fails response
{}\n\n".format(response.__dict__))
self.assertEqual(response.status_code,
status.HTTP_400_BAD_REQUEST,
"Creating a user without required fields is a bad
request")
def test_create_account(self):
""" Creating an account only works if there is no request.user and
all required fields provided """
starting_user_count = get_user_model().objects.count()
url = reverse('user-list')
data = {'email': 'te...@example.com', 'first_name': 'John',
'last_name': 'Doe',
'phone': '2065551234', 'institution': 'Test', 'groupLead':
'John',
'password': 'testpassword'}
response = self.client.post(url, data, format='json')
print("\n\ntest_create_account response
{}\n\n".format(response.__dict__))
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
"User API POST unsuccessful
{}".format(response.data))
self.assertEqual(get_user_model().objects.count(),
starting_user_count + 1,
"One user was created")
self.assertEqual(get_user_model().objects.get(email=data['email']).email,
'te...@example.com',
"Email exists in database {}".format(
get_user_model().objects.filter(email=data['email']).__dict__)
}}}
The test_create_account_fails method works and returns an expected
failure. The test_create_account fails because http/response.py line 152
can't find the 'headers' key. I'm not sure why....
{{{
Traceback (most recent call last):
File "/var/www/ann/ann/users/tests/test_account_creation.py", line 41,
in test_create_account
print("\n\ntest_create_account response {}\n\n".format(response))
File "/home/vagrant/.virtualenvs/ann/lib/python3.5/site-
packages/django/http/response.py", line 299, in __repr__
'content_type': self['Content-Type'],
File "/home/vagrant/.virtualenvs/ann/lib/python3.5/site-
packages/django/http/response.py", line 152, in __getitem__
return self._headers[header.lower()][1]
KeyError: 'content-type'
}}}
If I patch the code to:
{{{
def __getitem__(self, header):
if self._headers.get(header.lower()):
return self._headers[header.lower()][1]
return self._headers.get(header.lower())
}}}
then test_create_account returns the following object during a print:
{{{
test_create_account response {'resolver_match': <SimpleLazyObject:
<function Client.request.<locals>.<lambda> at 0x7f8399ed4400>>, 'using':
None, 'template_name': None, 'context': [[{'False': False, 'None': None,
'True': True}, {'activate_url': 'http://testserver/accounts/confirm-
email/MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ/', 'key':
'MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ', 'user': <User: John Doe>,
'current_site': <Site: ann.test.org>}], [{'False': False, 'None': None,
'True': True}, {'activate_url': 'http://testserver/accounts/confirm-
email/MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ/', 'key':
'MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ', 'user': <User: John Doe>,
'current_site': <Site: ann.test.org>}, {}], [{'False': False, 'None':
None, 'True': True}, {'activate_url': 'http://testserver/accounts/confirm-
email/MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ/', 'key':
'MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ', 'user': <User: John Doe>,
'current_site': <Site: ann.test.org>}], [{'False': False, 'None': None,
'True': True}, {'activate_url': 'http://testserver/accounts/confirm-
email/MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ/', 'key':
'MTU:1dB3Lm:43Wje1L2IirjhfKIBf_uzsUclZQ', 'user': <User: John Doe>,
'current_site': <Site: ann.test.org>}, {'user_display': 'John Doe'}]],
'_dont_enforce_csrf_checks': True, '_post_render_callbacks': [],
'_is_rendered': True, 'client': <rest_framework.test.APIClient object at
0x7f83997a2470>, 'cookies': <SimpleCookie:
csrftoken='HPkblAYrdPfbJs5c2OAc7vH0k89wuj1n7elaPP8VZhvaB7CcouQxjy6bV47s3jgR'
sessionid='f0ukkwdn00jyt1tx52r86c9fax1ut2yv'>, 'context_data': None,
'templates': [<django.template.base.Template object at 0x7f8399a57e10>,
<django.template.base.Template object at 0x7f8399adef98>,
<django.template.base.Template object at 0x7f8399ade748>,
<django.template.base.Template object at 0x7f8399adef28>], 'json
}}}
test_create_account_fails returns this object:
{{{
test_create_account_fails response {'context_data': None, 'template_name':
None, 'templates': [], 'resolver_match': <SimpleLazyObject: <function
Client.request.<locals>.<lambda> at 0x7fd5038941e0>>, 'closed': True,
'_is_rendered': True, 'status_code': 400, '_post_render_callbacks': [],
'_charset': None, '_reason_phrase': None, '_request': None, '_headers':
{'content-type': ('Content-Type', 'application/json'), 'allow': ('Allow',
'GET, POST, OPTIONS'), 'vary': ('Vary', 'Cookie'), 'x-frame-options': ('X
-Frame-Options', 'SAMEORIGIN')}, '_handler_class': None, 'using': None,
'exception': True, 'data': {'institution': ['This field is required.'],
'phone': ['This field is required.'], 'group_lead': ['This field is
required.'], 'password': ['This field is required.'], 'first_name': ['This
field is required.'], 'last_name': ['This field is required.']},
'accepted_renderer':
<djangorestframework_camel_case.render.CamelCaseJSONRenderer object at
0x7fd50356cb00>, 'content_type': None, 'accepted_media_type':
'application/json', 'client': <rest_framework.test.APIClient object at
0x7fd50356c630>, 'wsgi_request': <WSGIRequest: POST '/api/users'>,
'context': None, '_closable_objects': [<WSGIRequest: POST '/api/users'>],
'renderer_context': {'view': <ann.users.apiviews.UserViewSet object at
0x7fd50356c978>, 'args': (), 'response': <Response status_code=400,
"application/json">, 'request': <rest_framework.request.Request object at
0x7fd50356ca20>, 'kwargs': {}}, '_container': [b'{"institution":["This
field is required."],"phone":["This field is
required."],"groupLead":["This field is required."],"password":["This
field is required."],"firstName":["This field is
required."],"lastName":["This field is required."]}'], 'cookies':
<SimpleCookie: >, 'json': <function curry.<locals>._curried at
0x7fd503894510>, 'request': {'REQUEST_METHOD': 'POST', 'CONTENT_LENGTH':
28, 'wsgi.url_scheme': 'http', 'QUERY_STRING': '', 'wsgi.input':
<django.test.client.FakePayload object at 0x7fd5034d9908>, 'SERVER_PORT':
'80', 'CONTENT_TYPE': 'application/json; charset=None', 'PATH_INFO':
'/api/users'}, '_dont_enforce_csrf_checks': True}
}}}
Maybe this is a bug with Django Rest Framework or CamelCaseJSONParser, but
I'd expect http/response to have a more robust getter?
--
Ticket URL: <https://code.djangoproject.com/ticket/28218>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* status: new => closed
* resolution: => duplicate
Comment:
Duplicate of #27640, fixed in Django 1.11.
--
Ticket URL: <https://code.djangoproject.com/ticket/28218#comment:1>
Comment (by Denise Mauldin):
Replying to [comment:1 Tim Graham]:
> Duplicate of #27640, fixed in Django 1.11.
Except that upgrading to 1.11 from 1.10 is a pain. No plans to fix in
1.10?
--
Ticket URL: <https://code.djangoproject.com/ticket/28218#comment:2>
Comment (by Tim Graham):
No, it doesn't qualify for a backport. Per our
[https://docs.djangoproject.com/en/dev/internals/release-process
/#supported-versions supported versions policy], 1.10 is only receiving
security fixes.
--
Ticket URL: <https://code.djangoproject.com/ticket/28218#comment:3>