Данные файлового поля Django REST Framework в JSON

Как в Django REST Framework (DRF) поддерживать десериализацию base64 закодированных двоичных данных?

У меня есть модель:

class MyModel(Model):
   data = models.FileField(...)

и я хочу иметь возможность отправлять эти данные в кодировке base64, а не в многокомпонентной форме данных или «загрузке файла». Глядя на Parsers, только FileUploadParser и MultiPartParser, похоже, разбирают файлы.

Я хотел бы иметь возможность отправлять эти данные в чем-то вроде JSON (т.е. отправлять двоичные данные в data, а не files:

{
 'data':'...'
}

person Alex Rothberg    schedule 06.11.2014    source источник


Ответы (3)


Я решил это, создав новый Parser:

def get_B64_JSON_Parser(fields):
    class Impl(parsers.JSONParser):
        media_type = 'application/json+b64'

        def parse(self, *args, **kwargs):
            ret = super(Impl, self).parse(*args, **kwargs)
            for field in fields:
                ret[field] = SimpleUploadedFile(name=field, content=ret[field].decode('base64'))
            return ret
    return Impl

который я затем использую в View:

class TestModelViewSet(viewsets.ModelViewSet):
    parser_classes = [get_B64_JSON_Parser(('data_file',)),]
person Alex Rothberg    schedule 06.11.2014

Это старый вопрос, но для тех, кто ищет актуальное решение, есть плагин для DRF (drf_base64), который обрабатывает эту ситуацию. Это позволяет читать файлы, закодированные как строки base64 в запросе JSON.

Итак, учитывая модель вроде:

class MyModel(Model):
   data = models.FileField(...)

и ожидаемый json, например:

{
  "data": "data:image/png;base64,iVBORw0KGgoA ....",
  ...
}

Сериализацию (des) можно выполнить, просто импортируя из модулей drf_base вместо самого drf.

из drf_base64.serializers импортировать ModelSerializer из .models импортировать MyModel

class MyModel(ModelSerializer):

    class Meta:
        model = MyModel

Просто помните, что можно получить файл в кодировке base64 в javascript с помощью API FileReader.

person Francisco Puga    schedule 22.06.2017

Вероятно, вы можете сделать что-то умное на уровне сериализатора, но первое, что приходит на ум, это сделать это в представлении.

Шаг 1. Запишите файл. Что-то типа:

fh = open("/path/to/media/folder/fileToSave.ext", "wb")
fh.write(fileData.decode('base64'))
fh.close()

Шаг 2. Установите файл на модель. Что-то типа:

instance = self.get_object()
instance.file_field.name = 'folder/fileToSave.ext' # `file_field` was `data` in your example
instance.save()

Обратите внимание на абсолютный путь на шаге 1 и путь относительно папки мультимедиа на шаге 2.

Это должно по крайней мере заставить вас идти.

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

person Carlton Gibson    schedule 06.11.2014
comment
Похоже, что третий вариант декодирования двоичного кода в Serializer или View состоит в том, чтобы сделать это в Parser. Тогда мой вопрос будет заключаться в том, как написать синтаксический анализатор, который знает, какие поля base64 декодировать. - person Alex Rothberg; 06.11.2014
comment
Ну, в первом случае просто жестко закодируйте это. Если вам это нужно снова, есть параметр. - person Carlton Gibson; 06.11.2014
comment
Вы имеете в виду написать что-то вроде: parser_classes = (get_B64_JSON_Parser(('field_a',)),) - person Alex Rothberg; 06.11.2014
comment
Ага. Но, не задумываясь об этом, я не имею четкого представления о том, как будет работать этот парсер. Как вы собираетесь пройти аттестацию? Как вы собираетесь передавать вывод в FileField? И т. д. Я бы сделал это в представлении - person Carlton Gibson; 06.11.2014
comment
Парсер может вернуть DataAndFiles. где files['field_a'] = SimpleUploadedFile(name='fileToSave.ext', content=fileData.decode('base64')) - person Alex Rothberg; 06.11.2014