mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	* url() is deprecated in Django 3.1 * update given feedbacks on url() is deprecated in Django 3.1 * Fix test_urlpatterns.py to continue testing mixed re_path() and path() * Fix one missed reference Co-authored-by: sanjusci <sanju.sci9@gmail.com>
		
			
				
	
	
		
			473 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			473 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import os
 | 
						|
import tempfile
 | 
						|
import unittest
 | 
						|
 | 
						|
from django.http import HttpResponse
 | 
						|
from django.test import override_settings
 | 
						|
from django.urls import path, re_path
 | 
						|
 | 
						|
from rest_framework.compat import coreapi, coreschema
 | 
						|
from rest_framework.parsers import FileUploadParser
 | 
						|
from rest_framework.renderers import CoreJSONRenderer
 | 
						|
from rest_framework.response import Response
 | 
						|
from rest_framework.test import APITestCase, CoreAPIClient
 | 
						|
from rest_framework.views import APIView
 | 
						|
 | 
						|
 | 
						|
def get_schema():
 | 
						|
    return coreapi.Document(
 | 
						|
        url='https://api.example.com/',
 | 
						|
        title='Example API',
 | 
						|
        content={
 | 
						|
            'simple_link': coreapi.Link('/example/', description='example link'),
 | 
						|
            'headers': coreapi.Link('/headers/'),
 | 
						|
            'location': {
 | 
						|
                'query': coreapi.Link('/example/', fields=[
 | 
						|
                    coreapi.Field(name='example', schema=coreschema.String(description='example field'))
 | 
						|
                ]),
 | 
						|
                'form': coreapi.Link('/example/', action='post', fields=[
 | 
						|
                    coreapi.Field(name='example')
 | 
						|
                ]),
 | 
						|
                'body': coreapi.Link('/example/', action='post', fields=[
 | 
						|
                    coreapi.Field(name='example', location='body')
 | 
						|
                ]),
 | 
						|
                'path': coreapi.Link('/example/{id}', fields=[
 | 
						|
                    coreapi.Field(name='id', location='path')
 | 
						|
                ])
 | 
						|
            },
 | 
						|
            'encoding': {
 | 
						|
                'multipart': coreapi.Link('/example/', action='post', encoding='multipart/form-data', fields=[
 | 
						|
                    coreapi.Field(name='example')
 | 
						|
                ]),
 | 
						|
                'multipart-body': coreapi.Link('/example/', action='post', encoding='multipart/form-data', fields=[
 | 
						|
                    coreapi.Field(name='example', location='body')
 | 
						|
                ]),
 | 
						|
                'urlencoded': coreapi.Link('/example/', action='post', encoding='application/x-www-form-urlencoded', fields=[
 | 
						|
                    coreapi.Field(name='example')
 | 
						|
                ]),
 | 
						|
                'urlencoded-body': coreapi.Link('/example/', action='post', encoding='application/x-www-form-urlencoded', fields=[
 | 
						|
                    coreapi.Field(name='example', location='body')
 | 
						|
                ]),
 | 
						|
                'raw_upload': coreapi.Link('/upload/', action='post', encoding='application/octet-stream', fields=[
 | 
						|
                    coreapi.Field(name='example', location='body')
 | 
						|
                ]),
 | 
						|
            },
 | 
						|
            'response': {
 | 
						|
                'download': coreapi.Link('/download/'),
 | 
						|
                'text': coreapi.Link('/text/')
 | 
						|
            }
 | 
						|
        }
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def _iterlists(querydict):
 | 
						|
    if hasattr(querydict, 'iterlists'):
 | 
						|
        return querydict.iterlists()
 | 
						|
    return querydict.lists()
 | 
						|
 | 
						|
 | 
						|
def _get_query_params(request):
 | 
						|
    # Return query params in a plain dict, using a list value if more
 | 
						|
    # than one item is present for a given key.
 | 
						|
    return {
 | 
						|
        key: (value[0] if len(value) == 1 else value)
 | 
						|
        for key, value in
 | 
						|
        _iterlists(request.query_params)
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
def _get_data(request):
 | 
						|
    if not isinstance(request.data, dict):
 | 
						|
        return request.data
 | 
						|
    # Coerce multidict into regular dict, and remove files to
 | 
						|
    # make assertions simpler.
 | 
						|
    if hasattr(request.data, 'iterlists') or hasattr(request.data, 'lists'):
 | 
						|
        # Use a list value if a QueryDict contains multiple items for a key.
 | 
						|
        return {
 | 
						|
            key: value[0] if len(value) == 1 else value
 | 
						|
            for key, value in _iterlists(request.data)
 | 
						|
            if key not in request.FILES
 | 
						|
        }
 | 
						|
    return {
 | 
						|
        key: value
 | 
						|
        for key, value in request.data.items()
 | 
						|
        if key not in request.FILES
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
def _get_files(request):
 | 
						|
    if not request.FILES:
 | 
						|
        return {}
 | 
						|
    return {
 | 
						|
        key: {'name': value.name, 'content': value.read()}
 | 
						|
        for key, value in request.FILES.items()
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
class SchemaView(APIView):
 | 
						|
    renderer_classes = [CoreJSONRenderer]
 | 
						|
 | 
						|
    def get(self, request):
 | 
						|
        schema = get_schema()
 | 
						|
        return Response(schema)
 | 
						|
 | 
						|
 | 
						|
class ListView(APIView):
 | 
						|
    def get(self, request):
 | 
						|
        return Response({
 | 
						|
            'method': request.method,
 | 
						|
            'query_params': _get_query_params(request)
 | 
						|
        })
 | 
						|
 | 
						|
    def post(self, request):
 | 
						|
        if request.content_type:
 | 
						|
            content_type = request.content_type.split(';')[0]
 | 
						|
        else:
 | 
						|
            content_type = None
 | 
						|
 | 
						|
        return Response({
 | 
						|
            'method': request.method,
 | 
						|
            'query_params': _get_query_params(request),
 | 
						|
            'data': _get_data(request),
 | 
						|
            'files': _get_files(request),
 | 
						|
            'content_type': content_type
 | 
						|
        })
 | 
						|
 | 
						|
 | 
						|
class DetailView(APIView):
 | 
						|
    def get(self, request, id):
 | 
						|
        return Response({
 | 
						|
            'id': id,
 | 
						|
            'method': request.method,
 | 
						|
            'query_params': _get_query_params(request)
 | 
						|
        })
 | 
						|
 | 
						|
 | 
						|
class UploadView(APIView):
 | 
						|
    parser_classes = [FileUploadParser]
 | 
						|
 | 
						|
    def post(self, request):
 | 
						|
        return Response({
 | 
						|
            'method': request.method,
 | 
						|
            'files': _get_files(request),
 | 
						|
            'content_type': request.content_type
 | 
						|
        })
 | 
						|
 | 
						|
 | 
						|
class DownloadView(APIView):
 | 
						|
    def get(self, request):
 | 
						|
        return HttpResponse('some file content', content_type='image/png')
 | 
						|
 | 
						|
 | 
						|
class TextView(APIView):
 | 
						|
    def get(self, request):
 | 
						|
        return HttpResponse('123', content_type='text/plain')
 | 
						|
 | 
						|
 | 
						|
class HeadersView(APIView):
 | 
						|
    def get(self, request):
 | 
						|
        headers = {
 | 
						|
            key[5:].replace('_', '-'): value
 | 
						|
            for key, value in request.META.items()
 | 
						|
            if key.startswith('HTTP_')
 | 
						|
        }
 | 
						|
        return Response({
 | 
						|
            'method': request.method,
 | 
						|
            'headers': headers
 | 
						|
        })
 | 
						|
 | 
						|
 | 
						|
urlpatterns = [
 | 
						|
    path('', SchemaView.as_view()),
 | 
						|
    path('example/', ListView.as_view()),
 | 
						|
    re_path(r'^example/(?P<id>[0-9]+)/$', DetailView.as_view()),
 | 
						|
    path('upload/', UploadView.as_view()),
 | 
						|
    path('download/', DownloadView.as_view()),
 | 
						|
    path('text/', TextView.as_view()),
 | 
						|
    path('headers/', HeadersView.as_view()),
 | 
						|
]
 | 
						|
 | 
						|
 | 
						|
@unittest.skipUnless(coreapi, 'coreapi not installed')
 | 
						|
@override_settings(ROOT_URLCONF='tests.test_api_client')
 | 
						|
class APIClientTests(APITestCase):
 | 
						|
    def test_api_client(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        assert schema.title == 'Example API'
 | 
						|
        assert schema.url == 'https://api.example.com/'
 | 
						|
        assert schema['simple_link'].description == 'example link'
 | 
						|
        assert schema['location']['query'].fields[0].schema.description == 'example field'
 | 
						|
        data = client.action(schema, ['simple_link'])
 | 
						|
        expected = {
 | 
						|
            'method': 'GET',
 | 
						|
            'query_params': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_query_params(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['location', 'query'], params={'example': 123})
 | 
						|
        expected = {
 | 
						|
            'method': 'GET',
 | 
						|
            'query_params': {'example': '123'}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_session_headers(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        client.session.headers.update({'X-Custom-Header': 'foo'})
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['headers'])
 | 
						|
        assert data['headers']['X-CUSTOM-HEADER'] == 'foo'
 | 
						|
 | 
						|
    def test_query_params_with_multiple_values(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['location', 'query'], params={'example': [1, 2, 3]})
 | 
						|
        expected = {
 | 
						|
            'method': 'GET',
 | 
						|
            'query_params': {'example': ['1', '2', '3']}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_form_params(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['location', 'form'], params={'example': 123})
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'application/json',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'example': 123},
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_body_params(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['location', 'body'], params={'example': 123})
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'application/json',
 | 
						|
            'query_params': {},
 | 
						|
            'data': 123,
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_path_params(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['location', 'path'], params={'id': 123})
 | 
						|
        expected = {
 | 
						|
            'method': 'GET',
 | 
						|
            'query_params': {},
 | 
						|
            'id': '123'
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_multipart_encoding(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        with tempfile.NamedTemporaryFile() as temp:
 | 
						|
            temp.write(b'example file content')
 | 
						|
            temp.flush()
 | 
						|
            temp.seek(0)
 | 
						|
 | 
						|
            name = os.path.basename(temp.name)
 | 
						|
            data = client.action(schema, ['encoding', 'multipart'], params={'example': temp})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'multipart/form-data',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {},
 | 
						|
            'files': {'example': {'name': name, 'content': 'example file content'}}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_multipart_encoding_no_file(self):
 | 
						|
        # When no file is included, multipart encoding should still be used.
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        data = client.action(schema, ['encoding', 'multipart'], params={'example': 123})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'multipart/form-data',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'example': '123'},
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_multipart_encoding_multiple_values(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        data = client.action(schema, ['encoding', 'multipart'], params={'example': [1, 2, 3]})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'multipart/form-data',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'example': ['1', '2', '3']},
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_multipart_encoding_string_file_content(self):
 | 
						|
        # Test for `coreapi.utils.File` support.
 | 
						|
        from coreapi.utils import File
 | 
						|
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        example = File(name='example.txt', content='123')
 | 
						|
        data = client.action(schema, ['encoding', 'multipart'], params={'example': example})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'multipart/form-data',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {},
 | 
						|
            'files': {'example': {'name': 'example.txt', 'content': '123'}}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_multipart_encoding_in_body(self):
 | 
						|
        from coreapi.utils import File
 | 
						|
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        example = {'foo': File(name='example.txt', content='123'), 'bar': 'abc'}
 | 
						|
        data = client.action(schema, ['encoding', 'multipart-body'], params={'example': example})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'multipart/form-data',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'bar': 'abc'},
 | 
						|
            'files': {'foo': {'name': 'example.txt', 'content': '123'}}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    # URLencoded
 | 
						|
 | 
						|
    def test_urlencoded_encoding(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['encoding', 'urlencoded'], params={'example': 123})
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'application/x-www-form-urlencoded',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'example': '123'},
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_urlencoded_encoding_multiple_values(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['encoding', 'urlencoded'], params={'example': [1, 2, 3]})
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'application/x-www-form-urlencoded',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'example': ['1', '2', '3']},
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_urlencoded_encoding_in_body(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
        data = client.action(schema, ['encoding', 'urlencoded-body'], params={'example': {'foo': 123, 'bar': True}})
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'content_type': 'application/x-www-form-urlencoded',
 | 
						|
            'query_params': {},
 | 
						|
            'data': {'foo': '123', 'bar': 'true'},
 | 
						|
            'files': {}
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    # Raw uploads
 | 
						|
 | 
						|
    def test_raw_upload(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        with tempfile.NamedTemporaryFile(delete=False) as temp:
 | 
						|
            temp.write(b'example file content')
 | 
						|
            temp.flush()
 | 
						|
            temp.seek(0)
 | 
						|
 | 
						|
            name = os.path.basename(temp.name)
 | 
						|
            data = client.action(schema, ['encoding', 'raw_upload'], params={'example': temp})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'files': {'file': {'name': name, 'content': 'example file content'}},
 | 
						|
            'content_type': 'application/octet-stream'
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_raw_upload_string_file_content(self):
 | 
						|
        from coreapi.utils import File
 | 
						|
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        example = File('example.txt', '123')
 | 
						|
        data = client.action(schema, ['encoding', 'raw_upload'], params={'example': example})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'files': {'file': {'name': 'example.txt', 'content': '123'}},
 | 
						|
            'content_type': 'text/plain'
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_raw_upload_explicit_content_type(self):
 | 
						|
        from coreapi.utils import File
 | 
						|
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        example = File('example.txt', '123', 'text/html')
 | 
						|
        data = client.action(schema, ['encoding', 'raw_upload'], params={'example': example})
 | 
						|
 | 
						|
        expected = {
 | 
						|
            'method': 'POST',
 | 
						|
            'files': {'file': {'name': 'example.txt', 'content': '123'}},
 | 
						|
            'content_type': 'text/html'
 | 
						|
        }
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    # Responses
 | 
						|
 | 
						|
    def test_text_response(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        data = client.action(schema, ['response', 'text'])
 | 
						|
 | 
						|
        expected = '123'
 | 
						|
        assert data == expected
 | 
						|
 | 
						|
    def test_download_response(self):
 | 
						|
        client = CoreAPIClient()
 | 
						|
        schema = client.get('http://api.example.com/')
 | 
						|
 | 
						|
        data = client.action(schema, ['response', 'download'])
 | 
						|
        assert data.basename == 'download.png'
 | 
						|
        assert data.read() == b'some file content'
 |