#28218 closed Bug (duplicate)
KeyError 'content-type' http/response.py when printing response
Reported by: | Denise Mauldin | Owned by: | nobody |
---|---|---|---|
Component: | HTTP handling | Version: | 1.10 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hi all,
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': 'test@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': 'test@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, 'test@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?
Change History (3)
follow-up: 2 comment:1 by , 7 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
comment:2 by , 7 years ago
Replying to 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?
comment:3 by , 7 years ago
No, it doesn't qualify for a backport. Per our supported versions policy, 1.10 is only receiving security fixes.
Duplicate of #27640, fixed in Django 1.11.