0

I have uploaded directory using django and JavaScript. Now I am trying to download this directory from django admin. For this purpose I have followed this link click here. When I have uploaded directory in django, the admin created the following table. File name indicates the uploaded folder name.

enter image description here

If I click on the file name, it shows me following error. I want to download this directory as a zip file from django admin. Can anyone please help me with this?

enter image description here

Here is my model.py:

class Prearchive(models.Model):
    file = models.FileField(upload_to='media/', null=True) 
    file_name = models.CharField(max_length=500,primary_key=True)    
    file_id = models.ForeignKey(CreateScan, on_delete=models.CASCADE,default=1) 

    def _str_(self):
        return self.file_name 

admin.py:

from django.contrib import admin
from .models import CreateScan, Prearchive

# Register your models here.

class PrearchiveAdmin(admin.ModelAdmin):
    model=Prearchive
    list_display = ('file_name','file_id','file_link')
    def file_link(self, obj):
        if obj.file:
            return "<a href='%s' download>Download</a>" % (obj.file.url,)
        else:
            return "No attachment"
    file_link.allow_tags = True
    file_link.short_description = 'File Download'

admin.site.register(Prearchive , PrearchiveAdmin)

view.py:

@login_required
def downloadScanView(request,url):
    print('url',url)
    response = HttpResponse(content_type='application/zip')
    file_path = os.path.join(settings.MEDIA_ROOT, url)
    zip_download = ZipFile(response, 'w',ZIP_DEFLATED)
    if os.path.exists(file_path):
        for root, dir, files in os.walk(file_path):
            print('r = ',root)
            for file in files:
                zip_download.write(os.path.join(root,file))
        response['Content-Disposition'] = 'attachment; filename={}'.format(os.path.basename(url)+'.zip')
        return response
reasm001
  • 167
  • 1
  • 11
  • Celery task to zip those files to a tmp location, then serve when the files ready by notifying in an email which expires in 24 hours and then delete those temp zipped files. – frozenOne Jun 28 '20 at 16:44
  • Thanks for your reply. The problem is when I go into this url: http://127.0.0.1:8080/media/iit_0001_9_Unknown_aser4, I am having this 'Directory indexes are not allowed here.' error. I can not even see the files inside the directory. How can I get the files inside folder using this folder link? – reasm001 Jun 28 '20 at 17:00
  • You can't go to this url, because it's not defined within `django`, and the basic assumption is that if you are serving files for download you're doing that using s3 or a media storage backend. Have you defined the media root in you `settings.py` folder? – frozenOne Jun 28 '20 at 17:21
  • I am using media storage backend and defined it in settings.py. This is in my setting.py: MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media'). And I also set this (if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ) in my url.py. I have modified my question and attached my download view code in there. Can you please explain me a bit about it? Thanks in advance. – reasm001 Jun 28 '20 at 19:02
  • I am not sure why this is happening but the url I am getting is something like: /media/folder_name. My setting.MEDIA_ROOT is: /User/project/media. So when I try to use os.path.join(), it returns same path as url (/media/folder_name). It does not join the url with MEDIA_ROOT path. – reasm001 Jun 28 '20 at 19:21
  • Hi, it's working now. I tried to join absolute path with MEDIA_ROOT. That's why it could not find the file path properly. I took the base directory name from url and join with the MEDIA_ROOT. Now it's working. Hope I am doing it correctly. BTW, many thanks for your suggestion. – reasm001 Jun 28 '20 at 19:34
  • Everything works as intended then? If not let me know what doesn't, I'm a bit daft. – frozenOne Jun 28 '20 at 19:39
  • Actually, it is only working when I call downloadScanView from the template. I can not download it from django admin panel. Could you please give me suggestion for this? – reasm001 Jun 28 '20 at 20:12
  • Yep, you need to use MEDIA_ROOT in `file_link` function as well. This will help: https://stackoverflow.com/questions/50764746/how-to-download-file-from-django-admin – frozenOne Jun 28 '20 at 20:19
  • I have used it in file_link. No luck. It just shows the text 'Download' instead of creating any link. – reasm001 Jun 28 '20 at 20:45

1 Answers1

0

Create a view to download the file, and add urls.py entry for /media to this view.

views.py

def filedownload(request, filename):
    zf = zipfile.ZipFile('download.zip', 'w', zipfile.ZIP_DEFLATED)
    zf.write("media/" + filename)
    response = HttpResponse(zf, content_type='application/force-download')
    response['Content-Disposition'] = 'attachment; filename="download.zip"'
    return response

Main urls.py

path('media/', include('your_app.urls')

App urls.py

path("<filename>/", views.filezip, name="filedownload")
55abhilash
  • 332
  • 2
  • 9