Django Views: Когда request.data является диктом против QueryDict?
У меня возникли проблемы с тем, что request.data иногда dict
(особенно при тестировании) и иногда QueryDict
экземпляр (при использовании curl).
Это особенно проблема, потому что, по-видимому, существует большая разница при вызове представления с использованием curl следующим образом:
curl -X POST --data "some_float=1.23456789012123123" "http://localhost:8000/myview"
Или используя клиент django_webtest примерно так:
class APIViewTest(WebTest):
def test_testsomething(self):
self.app.post(url=url, params=json.dumps({some_float=1.26356756467}))
А затем приведение этого QueryDict к диктату, как так
new_dict = dict(**request.data)
my_float = float(new_dict['some_float'])
Все отлично работает в тестах, так как есть request.data
это dict
, но в производстве представление вылетает, потому что new_dict['some_float']
на самом деле список с одним элементом, а не как ожидается, с плавающей точкой.
Я подумал об устранении проблемы следующим образом:
if type(request.data) is dict:
new_dict = dict(**request.data)
else:
new_dict = dict(**request.data.dict())
что выглядит очень неправильно, так как тесты будут проверять только строку 2, а (некоторые? все?) рабочий код будет запускать строку 4.
Поэтому, хотя мне интересно, почему QueryDict ведет себя таким образом, я бы предпочел знать, почему и когда response.data является QueryDict
на первом месте. И как я могу использовать тесты Django для имитации этого поведения. Наличие разных условий для производства и тестирования систем всегда проблематично и иногда неизбежно, но в этом случае я чувствую, что это можно исправить. Или это специфическая проблема, связанная с django_webtest?
1 ответ
Ваш тест не является отражением вашего фактического вызова.
В своем тесте вы публикуете JSON, который затем доступен в виде комментария от request.data
, Но ваш вызов curl публикует стандартные данные формы, которые доступны как QueryDict. Это поведение управляется parsers
атрибут вашего представления или настройки DEFAULT_PARSER_CLASSES - и далее отметим, что это функциональность, специально предоставляемая django-rest-framework, которую вы должны были пометить в своем вопросе, а не сам Django.
На самом деле вы должны проверить то же самое, что и вы; отправьте JSON из curl или отправьте тест для публикации данных формы.
Когда ваш тип содержимого content_type "application/x-www-form-urlencoded", request.Data становится QueryDict.
см. класс FormParser.
https://github.com/encode/django-rest-framework/blob/master/rest_framework/parsers.py
А также
QueryDict имеет метод получения списков. но это не может принести продиктованное значение.
преобразовать имя str в массив
<input name="items[name]" value="Example">
<input name="items[count]" value="5">
https://pypi.org/project/html-json-forms/
И определить пользовательскую форму paser.
class CustomFormParser(FormParser):
"""
Parser for form data.
"""
media_type = 'application/x-www-form-urlencoded'
def parse(self, stream, media_type=None, parser_context=None):
"""
Parses the incoming bytestream as a URL encoded form,
and returns the resulting QueryDict.
"""
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
data = QueryDict(stream.read(), encoding=encoding)
return parse_json_form(data.dict()) # return dict
И перезаписать DEFAULT_PARSER_CLASSES.
https://www.django-rest-framework.org/api-guide/settings/