Je dois renvoyer le téléchargement du fichier généré sous la forme Django REST Réponse du framework. J'ai essayé ce qui suit:
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
Mais il renvoie un document msword sous la forme json
.
Comment puis-je faire commencer le téléchargement en tant que fichier?
J'ai résolu mon problème en enregistrant le fichier dans le dossier multimédia et en envoyant le lien vers le front-end.
@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)
Et géré cela comme dans mon front-end (AngularJS SPA)
$http(req).success(function (url) {
console.log(url);
window.location = url;
})
Cela peut fonctionner pour vous:
file_path = file_url
FilePointer = open(file_path,"r")
response = HttpResponse(FilePointer,content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'
return response.
Pour le code FrontEnd, reportez-vous à this
Voici un exemple de renvoi d'un téléchargement de fichier directement depuis DRF. L'astuce consiste à utiliser un rendu personnalisé afin que vous puissiez retourner une réponse directement à partir de la vue:
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
Remarque J'utilise un point de terminaison personnalisé download
au lieu du point de terminaison par défaut retrieve
, car cela permet de remplacer facilement le rendu uniquement pour ce point de terminaison au lieu de l'ensemble de la vue - et cela tend à pour donner un sens à la liste et aux détails pour renvoyer le JSON normal de toute façon. Si vous souhaitez retourner sélectivement un téléchargement de fichier, vous pouvez ajouter plus de logique au rendu personnalisé.
J'ai simplifié l'ensemble du processus dans ma réponse à une autre question similaire. N'hésitez pas à vous référer à ma réponse. Voici le lien vers ma réponse: https://stackoverflow.com/a/61075310/9142137
Dans ma réponse, j'ai montré comment télécharger des images (fichier) comme réponse pour votre API au lieu de renvoyer le fichier sous json
J'utilise DRF et j'ai trouvé un code de vue pour télécharger le fichier, qui serait comme
from rest_framework import generics
from Django.http import HttpResponse
from wsgiref.util import FileWrapper
class FileDownloadListAPIView(generics.ListAPIView):
def get(self, request, id, format=None):
queryset = Example.objects.get(id=id)
file_handle = queryset.file.path
document = open(file_handle, 'rb')
response = HttpResponse(FileWrapper(document), content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename="%s"' % queryset.file.name
return response
et url.py sera
path('download/<int:id>/',FileDownloadListAPIView.as_view())
J'utilise React.js en frontend et j'obtiens une réponse comme
handleDownload(id, filename) {
fetch(`http://127.0.0.1:8000/example/download/${id}/`).then(
response => {
response.blob().then(blob => {
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
console.log(url);
a.href = url;
a.download = filename;
a.click();
});
});
}
et après avoir réussi à télécharger un fichier qui s'ouvre également correctement et j'espère que cela fonctionnera. Merci