【问题标题】:Django rest framework: custom headers are different in client than unittestsDjango rest框架:客户端中的自定义标头与单元测试不同
【发布时间】:2018-09-29 06:10:50
【问题描述】:

我有一个 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']

我可以检查是否有'headers'键,但我不想仅仅为了通过单元测试而更改代码,它必须是某种方式来编写符合现实的单元测试,对吧?

我尝试使用:

from django.test import TestCase

还有:

from rest_framework.test import APITestCase

两者的结果相同。有什么解决办法吗?谢谢!

【问题讨论】:

  • 如果你在self.client.get调用中传入HTTP_LICENSE,它的表现是否如你所愿?
  • @sam 如果我在 self.client.get 中将 HTTP_LICENSE 作为标头传递,则可以使用 request.META['headers']['HTTP_LICENSE'] 检索它,这不是相同的行为与消费者请求一样:(。
  • @sam 我按照你说的尝试了:self.client.get(self.url, params=params, HTTP_LICENSE='12345') 并且成功了。谢谢!

标签: python django rest django-rest-framework


【解决方案1】:

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

在此过程中,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

然后将上面的内容传递到request 方法中的WSGIRequest 对象。 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

【讨论】:

    猜你喜欢
    • 2019-04-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多