Как вернуть сгенерированный файл загрузки с Django Rest Framework?

мне нужно вернуть сгенерированную загрузку файла в качестве ответа Django Rest Framework. Я попробовал следующее:

def retrieve(self, request, *args, **kwargs):
    template = webodt.ODFTemplate('test.odt')
    queryset = Pupils.objects.get(id=kwargs['pk'])
    serializer = StudentSerializer(queryset)
    context = dict(serializer.data)
    document = template.render(Context(context))
    doc = converter().convert(document, format='doc')
    res = HttpResponse(
        FileWrapper(doc),
        content_type='application/msword'
    )
    res['Content-Disposition'] = u'attachment; filename="%s_%s.zip"' % (context[u'surname'], context[u'name'])
    return res

но он возвращает документ msword как json.

Как заставить его начать загрузку в виде файла?

3 ответов


Это может сработать для вас:

file_path = file_url
FilePointer = open(file_path,"r")
response = HttpResponse(FilePointer,content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'

return response.

для кода интерфейса см. этой


Я решил свою проблему, сохранив файл в папке media и отправив ссылку на его интерфейс.

@permission_classes((permissions.IsAdminUser,))
class StudentDocxViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    def retrieve(self, request, *args, **kwargs):
        template = webodt.ODFTemplate('test.odt')
        queryset = Pupils.objects.get(id=kwargs['pk'])
        serializer = StudentSerializer(queryset)
        context = dict(serializer.data)
        document = template.render(Context(context))
        doc = converter().convert(document, format='doc')
        p = u'docs/cards/%s/%s_%s.doc' % (datetime.now().date(), context[u'surname'], context[u'name'])
        path = default_storage.save(p, doc)
        return response.Response(u'/media/' + path)

и обработал это, как в моем интерфейсе (AngularJS SPA)

$http(req).success(function (url) {
    console.log(url);
    window.location = url;
})

вот пример возврата загрузки файла непосредственно из DRF. Трюк состоит в том, чтобы использовать пользовательский рендерер, чтобы вы могли вернуть ответ непосредственно из представления:

from django.http import FileResponse
from rest_framework import viewsets, renderers
from rest_framework.decorators import action

class PassthroughRenderer(renderers.BaseRenderer):
    """
        Return data as-is. View should supply a Response.
    """
    media_type = ''
    format = ''
    def render(self, data, accepted_media_type=None, renderer_context=None):
        return data

class ExampleViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Example.objects.all()

    @action(methods=['get'], detail=True, renderer_classes=(PassthroughRenderer,))
    def download(self, *args, **kwargs):
        instance = self.get_object()

        # get an open file handle (I'm just using a file attached to the model for this example):
        file_handle = instance.file.open()

        # send file
        response = FileResponse(file_handle, content_type='whatever')
        response['Content-Length'] = instance.file.size
        response['Content-Disposition'] = 'attachment; filename="%s"' % instance.file.name

        return response

Примечание я использую пользовательскую конечную точку download вместо конечной точки по умолчанию retrieve, потому что это позволяет легко переопределить визуализатор только для этой конечной точки, а не для всего набора представлений-и в любом случае имеет смысл для list и detail возвращать обычный JSON. Если вы хотите выборочно возврат загрузки файла вы можете добавить больше логики в пользовательский рендеринг.