Execute these steps one by one:
- Create the view that will require authentication to download a file, as follows:
# myproject/apps/ideas/views.py
import os
from django.contrib.auth.decorators import login_required
from django.http import FileResponse, HttpResponseNotFound
from django.shortcuts import get_object_or_404
from django.utils.text import slugify
from .models import Idea
@login_required
def download_idea_picture(request, pk):
idea = get_object_or_404(Idea, pk=pk)
if idea.picture:
filename, extension =
os.path.splitext(idea.picture.file.name)
extension = extension[1:] # remove the dot
response = FileResponse(
idea.picture.file, content_type=f"image/{extension}"
)
slug = slugify(idea.title)[:100]
response["Content-Disposition"] = (
"attachment; filename="
f"{slug}.{extension}"
)
else:
response = HttpResponseNotFound(
content="Picture unavailable"
)
return response
- Add the download view to the URL configuration:
# myproject/apps/ideas/urls.py
from django.urls import path
from .views import download_idea_picture
urlpatterns = [
# …
path(
"<uuid:pk>/download-picture/",
download_idea_picture,
name="download_idea_picture",
),
]
- Set up the login view in our project URL configuration:
# myproject/urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path
urlpatterns = i18n_patterns(
# …
path("accounts/", include("django.contrib.auth.urls")),
path("ideas/", include(("myproject.apps.ideas.urls", "ideas"),
namespace="ideas")),
)
- Create a template for the login form, as shown in the following code:
{# registration/login.html #}
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<h1>{% trans "Login" %}</h1>
<form action="{{ request.path }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">{% trans
"Log in" %}</button>
</form>
{% endblock %}
- In the template of idea details, add a link to the download:
{# ideas/idea_detail.html #}
{% extends "base.html" %}
{% load i18n %}
{% block content %}
…
<a href="{% url 'ideas:download_idea_picture' pk=idea.pk %}"
class="btn btn-primary">{% trans "Download picture" %}</a>
{% endblock %}
You should restrict users from bypassing Django and downloading restricted files directly. To do so, on an Apache web server, you can put a .htaccess file in the media/ideas directory by using the following content if you are running Apache 2.4:
# media/ideas/.htaccess
Require all denied
When using django-imagekit, as shown in the examples throughout this book, the generated image versions will be stored and served from the media/CACHE directory, so our .htaccess configuration won't affect it.