Использование @api_view декоратора Django Rest Framework и таинственная ошибка
Я столкнулся с этой странной ошибкой, когда мой код работал нормально вчера (с помощью автоматических тестов), но сегодня сломался. По сути, создается впечатление, что декоратор @api_view ломается и не может применить метод. Вот ситуация:
У меня есть метод с именем 'advance_orders', и он упакован следующим образом:
@api_view(http_method_names=['POST'], hack=True)
@permission_classes((IsAuthenticated,))
@check_wallet_token
@disallow_disabled_users
def advance_orders(request):
# code that is irrelevant for this issue
ПРИМЕЧАНИЕ: hack = True - небольшое дополнение, которое я сделал для целей отладки после того, как впервые обнаружил ошибку.
Методы @check_wallet_token
а также @disallow_disabled_users
здесь также не имеет значения, и я на 99,99% уверен, что они не являются источником ошибки (так как они работали оштрафованы вчера и в / на других методах, которые переносятся аналогично)
URL-адрес для функции:re_path(r'^vendor/orders/advance/$', vendor.advance_orders, name='advance_order'),
Теперь в определенном тесте у меня есть:
client = RequestsClient()
# absolute_url == http://testserver/wallet/vendor/orders/advance/
# there are some helper methods which generate it...
# the headers are irrelevant honestly
r = client.post(absolute_url, headers=self.headers, data={"order_id": "asdf"})
print(r.text)
self.assertEqual(r.status_code, 400)
self.assertEqual(json.loads(r.text), {"display_message": "Missing order_id (int)."})
Тест не пройден и при печати текста ответа я нахожу:{"detail":"Method \"POST\" not allowed."}
Что не имеет смысла! Если я не делаю что-то явно не так, что я почти уверен, что нет.
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++
Теперь вот, когда я собираю больше доказательств. Я вхожу в исходный код DRF, установленного в моей виртуальной среде, и изменяю два метода для распечатки дополнительной отладочной информации.
Во views.py меняю views.APIView.dispatch()
следующее:
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
hack = False
if request.META['PATH_INFO'] == '/wallet/vendor/orders/advance/':
print("[HACK - views.py] Method identified as advance_order")
hack = True
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
print("[HACK - views.py] list of http_method_names associated with the function: {}".format(self.http_method_names))
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
# and so on as usual...
Другой метод, который я изменяю, decorators.api_view()
чтобы:
def api_view(http_method_names=None, exclude_from_schema=False, hack=False):
"""
Decorator that converts a function-based view into an APIView subclass.
Takes a list of allowed methods for the view as an argument.
"""
http_method_names = ['GET'] if (http_method_names is None) else http_method_names
if hack:
print("[HACK - decorators.py] Provided http_method_names: {}".format(http_method_names))
# and so on as usual...
Теперь я запускаю свои тесты, используя ./manage.py test Wallet.tests.test_api_vendors.API_VendorTestCase --failfast
и на печать результатов мы имеем:
[HACK - decorators.py] Provided http_method_names: ['POST']
System check identified no issues (0 silenced).
[HACK - views.py] Method identified as advance_order
[HACK - views.py] list of http_method_names associated with the function: ['get', 'options']
{"detail":"Method \"POST\" not allowed."}
F
======================================================================
FAIL: test_advance_order (Wallet.tests.test_api_vendors.API_VendorTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/mnt/CommonShare/Code/DVM/APOGEE/Wallet/tests/test_api_vendors.py", line 231, in test_advance_order
self.assertEqual(r.status_code, 400)
AssertionError: 405 != 400
----------------------------------------------------------------------
Ran 1 test in 0.377s
FAILED (failures=1)
Destroying test database for alias 'default'...
Это оставляет меня в тупике, так как это означает, что декоратор распознал, что я хотел разрешить метод "POST", но затем, когда мое представление "advance_order" выполнено, "POST" не включается в список разрешенных методов.
Итак, мой вопрос: ошибка с моей стороны? Если так, то как? Иначе, что я могу сделать, чтобы решить такую проблему? (удаление файлов __pycache__ не сработало).
PS Прошу прощения за очень многословный вопрос, я просто хочу быть очень ясным о моей проблеме.