Download uploaded files only from Django Admin
Tags: django
Published: 2022-07-25 18:02:09

---
title: Download uploaded files only from Django Admin
published: true
date: 2022-07-25 17:58:21 UTC
tags: Django
canonical_url: https://www.rockandnull.com/django-download-file-on-button-click/
---

 ![Download uploaded files only from Django Admin](https://images.unsplash.com/photo-1634979149798-e9a118734e93?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fHNlY3VyZXxlbnwwfHx8fDE2NTg3NzE2MDc&ixlib=rb-1.2.1&q=80&w=2000)

You can relatively easily upload a file to Django and save it into a location in your filesystem using a `Model`. And it's quite standard to set up serving those uploaded files when users need to view them.

An exceptionally specific, yet I think common case is for those files to be only viewable by the admins. For instance, if the user needs to upload a verification document for the admins to review before granting the user full access.

In those cases, the standard process of setting up [static file deployment](https://docs.djangoproject.com/en/4.0/howto/static-files/deployment/) might not be enough. Those uploaded media files should only be downloadable from the admin interface. Let's see how this can be accomplished using a custom admin view.

## Prerequisites

Firstly, you would need to set up a custom admin site as [described here](https://dev.to/mavris/django-admin-custom-pages-4dlh-temp-slug-6922293).

Secondly, your Model should contain a `FileField` :

```
class CustomUserProfile(models.Model):
    # [...] Other fields
    id_proof = models.FileField(upload_to='id_proof')
```

_models.py_

## View

You will need a view that will take as a parameter the primary key of the object and will return the bytes of the file. An `HttpResponse` with the file contents along with some additional headers will do the trick.

```
class IdProofView(View):

    def get(self, request, pk):
        user_profile = CustomUserProfile.objects.get(pk=pk)
        filename = os.path.basename(user_profile.id_proof.name)
        response = HttpResponse(user_profile.id_proof)
        response['Content-Disposition'] = \
        			f'attachment; filename={filename}'
        return response

```

_views.py_

Then wire it up in your custom admin's URL dispatcher (see this for [how to set up a custom admin site](https://dev.to/mavris/django-admin-custom-pages-4dlh-temp-slug-6922293)). Notice that you are wrapping the call to your view with `admin_view()`. This will protect it from unauthorized access. Only staff members will be able to download the file which is the behavior we want.

```
class CustomAdminSite(AdminSite):

    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            # [...] Other views for your custom admin
            path('id_proof/<int:pk>', \
            self.admin_view(IdProofView.as_view()), name='id_proof'),
           
        ]
        return my_urls + urls
```

_admin.py_

## ModelAdmin

Finally, we need to show the "secure" link to the file in the admin interface. We need a `ModelAdmin` that generates the link, if it exists, and shows it as a read-only property. Optionally, you can hide the default field in the `ModelAdmin` that will not work anyway, if you haven't set up media files serving.

```
class CustomUserProfileModelAdmin(admin.ModelAdmin):
    readonly_fields = ('id_proof_url',)
    exclude = ('id_proof',)

    def id_proof_url(self, instance):
        if instance.id_proof is None:
            return '-'
        return format_html(
            f'<a href="{reverse("admin:id_proof", \
            kwargs={"pk": instance.pk})}"target="_blank">Download</a>',
        )
        
admin.register(CustomUser, CustomUserModelAdmin)
```

_admin.py_

Hopefully, you got an idea of how to securely serve files defined in models to staff users via the admin interface.

Happy coding!