Django休息框架:客户端的自定义标头与单元测试不同

时间:2018-04-18 21:24:06

标签: python django rest django-rest-framework

我有一个Django Rest API,然后是一个使用此API的客户端。

我使用客户端中的请求传递自定义标头:

r = requests.get(url, params=params, headers={'license': '12345'})

然后在API中,在我的自定义权限中,我得到如下标题:

app_license = request.META['HTTP_LICENSE']

出于安全原因,我知道django rewrites the custom headers,所以它运作正常。

我的问题是当我在Django rest API中编写单元测试时:

response = self.client.get(self.url, params=params, headers={'license': '12345'})

然后提出:

KeyError: 'HTTP_LICENSE'

但是,如果我改变这样的代码,测试会毫无问题地通过,但消费者不能正常工作:

request.META['headers']['license']

我可以检查是否有“标题”键但我不想更改代码只是为了通过unittest,它必须是某种方式来编写一个与现实相匹配的单元测试,对吗?

我试图使用:

from django.test import TestCase

from rest_framework.test import APITestCase

两者都有相同的结果。有什么解决方案吗?谢谢!

1 个答案:

答案 0 :(得分:3)

TL; DR - 如果您想在META中显示某些内容,请将其设为kwargclient.get方法与requests.get的签名不同。

这是因为self.client.get的kwargs将直接映射到HTTP属性。

拿一个look at the source。您会注意到堆栈是:

  1. get
  2. generic
  3. request
  4. _base_environ
  5. 在此过程中,kwargs会被带到_base_environ,只有很少的改动。然后他们会合并到一个字典中,其中包含您期望的所有基本标题:

        # This is a minimal valid WSGI environ dictionary, plus:
        # - HTTP_COOKIE: for cookie support,
        # - REMOTE_ADDR: often useful, see #8551.
        # See http://www.python.org/dev/peps/pep-3333/#environ-variables
        environ = {
            'HTTP_COOKIE': self.cookies.output(header='', sep='; '),
            'PATH_INFO': '/',
            'REMOTE_ADDR': '127.0.0.1',
            'REQUEST_METHOD': 'GET',
            'SCRIPT_NAME': '',
            'SERVER_NAME': 'testserver',
            'SERVER_PORT': '80',
            'SERVER_PROTOCOL': 'HTTP/1.1',
            'wsgi.version': (1, 0),
            'wsgi.url_scheme': 'http',
            'wsgi.input': FakePayload(b''),
            'wsgi.errors': self.errors,
            'wsgi.multiprocess': True,
            'wsgi.multithread': False,
            'wsgi.run_once': False,
        }
        environ.update(self.defaults)
        environ.update(request)
        return environ
    

    然后将上述内容传递到WSGIRequest方法中的request对象。 That class then takes the provided environ dict and assigns it to the META property:

    class WSGIRequest(HttpRequest):
        def __init__(self, environ):
            script_name = get_script_name(environ)
            # If PATH_INFO is empty (e.g. accessing the SCRIPT_NAME URL without a
            # trailing slash), operate as if '/' was requested.
            path_info = get_path_info(environ) or '/'
    
            ##############################
            ##                          ##
            ## This is the line you're  ##
            ##       looking for.       ##
            ##                          ##
            ##############################
            self.environ = environ
            self.path_info = path_info