# Парсеры

***

источник:

* parsers.py

***

## Парсеры

> Взаимодействующие с машинами веб-сервисы обычно используют более структурированные форматы для отправки данных, чем данные формы, поскольку они отправляют более сложные данные, чем простые формы
>
> — Malcom Tredinnick, [Django developers group](https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion)

DRF включает ряд встроенных классов `Parser`, которые позволяют принимать запросы с различными типами носителей. Также есть поддержка определения собственных парсеров, что дает вам гибкость в определении типов медиа, которые принимает ваш API.

### Как определяется синтаксический анализатор

Набор допустимых парсеров для представления всегда определяется как список классов. Когда происходит обращение к `request.data`, DRF изучает заголовок `Content-Type` входящего запроса и определяет, какой парсер использовать для разбора содержимого запроса.

***

**Примечание**: При разработке клиентских приложений всегда помните о том, что при отправке данных в HTTP-запросе нужно обязательно устанавливать заголовок `Content-Type`.

Если вы не зададите тип содержимого, большинство клиентов по умолчанию будут использовать `'application/x-www-form-urlencoded'`, что может оказаться не тем, чего вы хотели.

В качестве примера, если вы отправляете закодированные данные `json` с помощью jQuery с методом [.ajax()](https://api.jquery.com/jQuery.ajax/), вы должны обязательно включить параметр `contentType: 'application/json'`.

***

### Настройка парсеров

Набор парсеров по умолчанию можно задать глобально, используя параметр `DEFAULT_PARSER_CLASSES`. Например, следующие настройки разрешают только запросы с содержимым `JSON`, вместо стандартного JSON или данных формы.

```python
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
    ]
}
```

Вы также можете установить парсеры, используемые для отдельного представления или набора представлений, используя представления на основе класса `APIView`.

```python
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    """
    A view that can accept POST requests with JSON content.
    """
    parser_classes = [JSONParser]

    def post(self, request, format=None):
        return Response({'received data': request.data})
```

Или, если вы используете декоратор `@api_view` с представлениями, основанными на функциях.

```python
from rest_framework.decorators import api_view
from rest_framework.decorators import parser_classes
from rest_framework.parsers import JSONParser

@api_view(['POST'])
@parser_classes([JSONParser])
def example_view(request, format=None):
    """
    A view that can accept POST requests with JSON content.
    """
    return Response({'received data': request.data})
```

***

## API Reference

### JSONParser

Разбирает `JSON` содержимое запроса. `request.data` будет заполнен словарем данных.

**.media\_type**: `application/json`.

### FormParser

Разбирает содержимое HTML-формы. `request.data` будет заполнен `QueryDict` данных.

Для полной поддержки данных HTML-формы обычно требуется использовать `FormParser` и `MultiPartParser` вместе.

**.media\_type**: `application/x-www-form-urlencoded`.

### MultiPartParser

Разбирает содержимое многокомпонентной HTML-формы, которая поддерживает загрузку файлов. `request.data` и `request.FILES` будут заполнены `QueryDict` и `MultiValueDict` соответственно.

Для полной поддержки данных HTML-формы обычно требуется использовать `FormParser` и `MultiPartParser` вместе.

**.media\_type**: `multipart/form-data`.

### FileUploadParser

Разбирает необработанное содержимое загружаемого файла. Свойство `request.data` будет представлять собой словарь с единственным ключом `'file'`, содержащим загруженный файл.

Если представление, используемое с `FileUploadParser`, вызывается с именованным аргументом URL `filename`, то этот аргумент будет использоваться в качестве имени файла.

Если он вызывается без именованного аргумента URL `filename`, то клиент должен установить имя файла в HTTP-заголовке `Content-Disposition`. Например, `Content-Disposition: attachment; filename=upload.jpg`.

**.media\_type**: `*/*`

**Примечания:**

* `FileUploadParser` предназначен для использования с собственными клиентами, которые могут загружать файл как запрос необработанных данных. Для веб-загрузки или для собственных клиентов с поддержкой многочастной загрузки вместо него следует использовать `MultiPartParser`.
* Поскольку `media_type` этого парсера соответствует любому типу содержимого, `FileUploadParser` обычно должен быть единственным парсером, установленным в представлении API.
* `FileUploadParser` учитывает стандартную настройку Django `FILE_UPLOAD_HANDLERS` и атрибут `request.upload_handlers`. Более подробную информацию смотрите в [документации Django](https://docs.djangoproject.com/en/stable/topics/http/file-uploads/#upload-handlers).

**Базовый пример использования:**

```python
# views.py
class FileUploadView(views.APIView):
    parser_classes = [FileUploadParser]

    def put(self, request, filename, format=None):
        file_obj = request.data['file']
        # ...
        # do some stuff with uploaded file
        # ...
        return Response(status=204)

# urls.py
urlpatterns = [
    # ...
    re_path(r'^upload/(?P<filename>[^/]+)$', FileUploadView.as_view())
]
```

***

## Пользовательские синтаксические анализаторы

Для реализации пользовательского парсера необходимо переопределить `BaseParser`, установить свойство `.media_type` и реализовать метод `.parse(self, stream, media_type, parser_context)`.

Метод должен возвращать данные, которые будут использоваться для заполнения свойства `request.data`.

Аргументами, передаваемыми в `.parse()`, являются:

#### stream

Потокоподобный объект, представляющий тело запроса.

#### media\_type

Необзательно. Если указано, это тип носителя содержимого входящего запроса.

В зависимости от заголовка `Content-Type:` запроса, он может быть более конкретным, чем атрибут `media_type` рендерера, и может включать параметры типа медиа. Например, `"text/plain; charset=utf-8"`.

#### parser\_context

Необзательно. Если этот аргумент указан, то он будет представлять собой словарь, содержащий любой дополнительный контекст, который может потребоваться для разбора содержимого запроса.

По умолчанию сюда входят следующие ключи: `view`, `request`, `args`, `kwargs`.

### Пример

Ниже приведен пример анализатора обычного текста, который заполнит свойство `request.data` строкой, представляющей тело запроса.

```python
class PlainTextParser(BaseParser):
    """
    Plain text parser.
    """
    media_type = 'text/plain'

    def parse(self, stream, media_type=None, parser_context=None):
        """
        Simply return a string representing the body of the request.
        """
        return stream.read()
```

***

## Пакеты сторонних производителей

Также доступны следующие пакеты сторонних производителей.

### YAML

[REST framework YAML](https://jpadilla.github.io/django-rest-framework-yaml/) обеспечивает поддержку разбора и рендеринга [YAML](http://www.yaml.org/). Ранее он был включен непосредственно в пакет DRF, а теперь поддерживается как сторонний пакет.

**Установка и настройка**

Установите с помощью pip.

```bash
$ pip install djangorestframework-yaml
```

Измените настройки DRF.

```python
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_yaml.parsers.YAMLParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_yaml.renderers.YAMLRenderer',
    ],
}
```

### XML

[REST Framework XML](https://jpadilla.github.io/django-rest-framework-xml/) предоставляет простой неформальный формат XML. Ранее он был включен непосредственно в пакет DRF, а теперь поддерживается как сторонний пакет.

**Установка и настройка**

Установите с помощью pip.

```bash
$ pip install djangorestframework-xml
```

Измените настройки DRF.

```python
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_xml.parsers.XMLParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_xml.renderers.XMLRenderer',
    ],
}
```

### MessagePack

[MessagePack](https://github.com/juanriaza/django-rest-framework-msgpack) - это быстрый и эффективный формат двоичной сериализации. [Juan Riaza](https://github.com/juanriaza) поддерживает пакет [djangorestframework-msgpack](https://github.com/juanriaza/django-rest-framework-msgpack), который обеспечивает поддержку рендеринга и парсера MessagePack для DRF.

### CamelCase JSON

[djangorestframework-camel-case](https://github.com/vbabiy/djangorestframework-camel-case) предоставляет рендереры и парсеры JSON в верблюжьем регистре для DRF. Это позволяет сериализаторам использовать имена полей в стиле Python с подчеркиванием, но отображать их в API как имена полей в верблюжьем регистре в стиле Javascript. Поддерживается [Виталием Бабием](https://github.com/vbabiy).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ilyachch.gitbook.io/django-rest-framework-russian-documentation/overview/navigaciya-po-api/parsers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
