mirror of
				https://github.com/django/django.git
				synced 2025-11-03 21:25:09 +00:00 
			
		
		
		
	Fixed #3160 -- Added the ability to control the content type in a test client POST request. This is to allow easier testing of json-rpc/xml-rpc/soap etc interfaces. Thanks to Mikeal Rogers for the suggestion, and Ben <afternoon@uk2.net> for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4529 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		
							parent
							
								
									4a85a75fb0
								
							
						
					
					
						commit
						d6d51c9546
					
				
					 5 changed files with 60 additions and 21 deletions
				
			
		| 
						 | 
					@ -9,6 +9,9 @@ from django.http import urlencode, SimpleCookie
 | 
				
			||||||
from django.test import signals
 | 
					from django.test import signals
 | 
				
			||||||
from django.utils.functional import curry
 | 
					from django.utils.functional import curry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOUNDARY = 'BoUnDaRyStRiNg'
 | 
				
			||||||
 | 
					MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClientHandler(BaseHandler):
 | 
					class ClientHandler(BaseHandler):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    A HTTP Handler that can be used for testing purposes.
 | 
					    A HTTP Handler that can be used for testing purposes.
 | 
				
			||||||
| 
						 | 
					@ -184,19 +187,20 @@ class Client:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.request(**r)
 | 
					        return self.request(**r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, path, data={}, **extra):
 | 
					    def post(self, path, data={}, content_type=MULTIPART_CONTENT, **extra):
 | 
				
			||||||
        "Request a response from the server using POST."
 | 
					        "Request a response from the server using POST."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        BOUNDARY = 'BoUnDaRyStRiNg'
 | 
					        if content_type is MULTIPART_CONTENT:
 | 
				
			||||||
 | 
					            post_data = encode_multipart(BOUNDARY, data)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            post_data = data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        encoded = encode_multipart(BOUNDARY, data)
 | 
					 | 
				
			||||||
        stream = StringIO(encoded)
 | 
					 | 
				
			||||||
        r = {
 | 
					        r = {
 | 
				
			||||||
            'CONTENT_LENGTH': len(encoded),
 | 
					            'CONTENT_LENGTH': len(post_data),
 | 
				
			||||||
            'CONTENT_TYPE':   'multipart/form-data; boundary=%s' % BOUNDARY,
 | 
					            'CONTENT_TYPE':   content_type,
 | 
				
			||||||
            'PATH_INFO':      path,
 | 
					            'PATH_INFO':      path,
 | 
				
			||||||
            'REQUEST_METHOD': 'POST',
 | 
					            'REQUEST_METHOD': 'POST',
 | 
				
			||||||
            'wsgi.input':     stream,
 | 
					            'wsgi.input':     StringIO(post_data),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        r.update(extra)
 | 
					        r.update(extra)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -217,15 +217,21 @@ can be invoked on the ``Client`` instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        http://yoursite.com/customers/details/?name=fred&age=7
 | 
					        http://yoursite.com/customers/details/?name=fred&age=7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``post(path, data={})``
 | 
					``post(path, data={}, content_type=MULTIPART_CONTENT)``
 | 
				
			||||||
    Make a POST request on the provided ``path``. The key-value pairs in the
 | 
					    Make a POST request on the provided ``path``. If you provide a content type
 | 
				
			||||||
    data dictionary will be used to create the POST data payload. This payload
 | 
					    (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be 
 | 
				
			||||||
    will be transmitted with the mimetype ``multipart/form-data``.
 | 
					    sent as-is in the POST request, using the content type in the HTTP 
 | 
				
			||||||
 | 
					    ``Content-Type`` header.
 | 
				
			||||||
    However submitting files is a special case. To POST a file, you need only
 | 
					    
 | 
				
			||||||
 | 
					    If you do not provide a value for ``content_type``, the values in 
 | 
				
			||||||
 | 
					    ``data`` will be transmitted with a content type of ``multipart/form-data``.
 | 
				
			||||||
 | 
					    The key-value pairs in the data dictionary will be encoded as a multipart
 | 
				
			||||||
 | 
					    message and used to create the POST data payload.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Submitting files is a special case. To POST a file, you need only
 | 
				
			||||||
    provide the file field name as a key, and a file handle to the file you wish to
 | 
					    provide the file field name as a key, and a file handle to the file you wish to
 | 
				
			||||||
    upload as a value. The Test Client will populate the two POST fields (i.e.,
 | 
					    upload as a value. The Test Client will populate the two POST fields (i.e.,
 | 
				
			||||||
    ``field`` and ``field_file``) required by FileField. For example::
 | 
					    ``field`` and ``field_file``) required by Django's FileField. For example::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        c = Client()
 | 
					        c = Client()
 | 
				
			||||||
        f = open('wishlist.doc')
 | 
					        f = open('wishlist.doc')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ class ClientTest(unittest.TestCase):
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # Check some response details
 | 
					        # Check some response details
 | 
				
			||||||
        self.assertEqual(response.status_code, 200)
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
        self.assertEqual(response.template.name, 'Empty POST Template')
 | 
					        self.assertEqual(response.template.name, 'Empty GET Template')
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    def test_empty_post(self):
 | 
					    def test_empty_post(self):
 | 
				
			||||||
        "POST an empty dictionary to a view"
 | 
					        "POST an empty dictionary to a view"
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ class ClientTest(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(response.status_code, 200)
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
        self.assertEqual(response.template.name, 'Empty POST Template')
 | 
					        self.assertEqual(response.template.name, 'Empty POST Template')
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    def test_post_view(self):
 | 
					    def test_post(self):
 | 
				
			||||||
        "POST some data to a view"
 | 
					        "POST some data to a view"
 | 
				
			||||||
        post_data = {
 | 
					        post_data = {
 | 
				
			||||||
            'value': 37
 | 
					            'value': 37
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,14 @@ class ClientTest(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(response.template.name, 'POST Template')
 | 
					        self.assertEqual(response.template.name, 'POST Template')
 | 
				
			||||||
        self.failUnless('Data received' in response.content)
 | 
					        self.failUnless('Data received' in response.content)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					    def test_raw_post(self):
 | 
				
			||||||
 | 
					        test_doc = """<?xml version="1.0" encoding="utf-8"?><library><book><title>Blink</title><author>Malcolm Gladwell</author></book></library>"""
 | 
				
			||||||
 | 
					        response = self.client.post("/test_client/raw_post_view/", test_doc,
 | 
				
			||||||
 | 
					                                    content_type="text/xml")
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
 | 
					        self.assertEqual(response.template.name, "Book template")
 | 
				
			||||||
 | 
					        self.assertEqual(response.content, "Blink - Malcolm Gladwell")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_redirect(self):
 | 
					    def test_redirect(self):
 | 
				
			||||||
        "GET a URL that redirects elsewhere"
 | 
					        "GET a URL that redirects elsewhere"
 | 
				
			||||||
        response = self.client.get('/test_client/redirect_view/')
 | 
					        response = self.client.get('/test_client/redirect_view/')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ import views
 | 
				
			||||||
urlpatterns = patterns('',
 | 
					urlpatterns = patterns('',
 | 
				
			||||||
    (r'^get_view/$', views.get_view),
 | 
					    (r'^get_view/$', views.get_view),
 | 
				
			||||||
    (r'^post_view/$', views.post_view),
 | 
					    (r'^post_view/$', views.post_view),
 | 
				
			||||||
 | 
					    (r'^raw_post_view/$', views.raw_post_view),
 | 
				
			||||||
    (r'^redirect_view/$', views.redirect_view),
 | 
					    (r'^redirect_view/$', views.redirect_view),
 | 
				
			||||||
    (r'^login_protected_view/$', views.login_protected_view),
 | 
					    (r'^login_protected_view/$', views.login_protected_view),
 | 
				
			||||||
    (r'^session_view/$', views.session_view),
 | 
					    (r'^session_view/$', views.session_view),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					from xml.dom.minidom import parseString
 | 
				
			||||||
from django.template import Context, Template
 | 
					from django.template import Context, Template
 | 
				
			||||||
from django.http import HttpResponse, HttpResponseRedirect
 | 
					from django.http import HttpResponse, HttpResponseRedirect
 | 
				
			||||||
from django.contrib.auth.decorators import login_required
 | 
					from django.contrib.auth.decorators import login_required
 | 
				
			||||||
| 
						 | 
					@ -13,15 +14,34 @@ def post_view(request):
 | 
				
			||||||
    """A view that expects a POST, and returns a different template depending
 | 
					    """A view that expects a POST, and returns a different template depending
 | 
				
			||||||
    on whether any POST data is available
 | 
					    on whether any POST data is available
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    if request.POST:
 | 
					    if request.method == 'POST':
 | 
				
			||||||
        t = Template('Data received: {{ data }} is the value.', name='POST Template')
 | 
					        if request.POST:
 | 
				
			||||||
        c = Context({'data': request.POST['value']})
 | 
					            t = Template('Data received: {{ data }} is the value.', name='POST Template')
 | 
				
			||||||
 | 
					            c = Context({'data': request.POST['value']})
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            t = Template('Viewing POST page.', name='Empty POST Template')
 | 
				
			||||||
 | 
					            c = Context()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        t = Template('Viewing POST page.', name='Empty POST Template')
 | 
					        t = Template('Viewing GET page.', name='Empty GET Template')
 | 
				
			||||||
        c = Context()
 | 
					        c = Context()
 | 
				
			||||||
        
 | 
					    
 | 
				
			||||||
    return HttpResponse(t.render(c))
 | 
					    return HttpResponse(t.render(c))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					def raw_post_view(request):
 | 
				
			||||||
 | 
					    """A view which expects raw XML to be posted and returns content extracted
 | 
				
			||||||
 | 
					    from the XML"""
 | 
				
			||||||
 | 
					    if request.method == 'POST':
 | 
				
			||||||
 | 
					        root = parseString(request.raw_post_data)
 | 
				
			||||||
 | 
					        first_book = root.firstChild.firstChild
 | 
				
			||||||
 | 
					        title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
 | 
				
			||||||
 | 
					        t = Template("{{ title }} - {{ author }}", name="Book template")
 | 
				
			||||||
 | 
					        c = Context({"title": title, "author": author})
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        t = Template("GET request.", name="Book GET template")
 | 
				
			||||||
 | 
					        c = Context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return HttpResponse(t.render(c))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def redirect_view(request):
 | 
					def redirect_view(request):
 | 
				
			||||||
    "A view that redirects all requests to the GET view"
 | 
					    "A view that redirects all requests to the GET view"
 | 
				
			||||||
    return HttpResponseRedirect('/test_client/get_view/')
 | 
					    return HttpResponseRedirect('/test_client/get_view/')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue