CODE WITH SIBIN

Solving Real Problems with Real Code


Django Jinja Templates: File Upload, List, Download, and Delete

This complete guide will walk you through creating a Django application that handles file uploads, displays a list of uploaded files, allows downloading files, and provides delete functionality - all using Jinja templates.

Step 1: Set Up Your Django Project

First, create a new Django project and app:

django-admin startproject filemanager
cd filemanager
python manage.py startapp files

Step 2: Install Required Packages

Install Django and Jinja2:

pip install django jinja2

Step 3: Configure Django Settings

In filemanager/settings.py:

  1. Add your app to INSTALLED_APPS:
INSTALLED_APPS = [
    # ...
    'files',
]
  1. Configure Jinja2 as a template backend:
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'environment': 'filemanager.jinja2.environment',
            'context_processors': [
                'django.template.context_processors.request',
            ],
        },
    },
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
  1. Set up media files configuration:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  1. Create a jinja2.py file in your project directory (filemanager/jinja2.py):
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

def environment(**options):
    env = Environment(**options)
    env.globals.update({
        'static': staticfiles_storage.url,
        'url': reverse,
    })
    return env

Step 4: Create the File Model

In files/models.py:

from django.db import models

class UploadedFile(models.Model):
    file = models.FileField(upload_to='uploads/')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=255, blank=True)
    size = models.PositiveIntegerField(default=0)
    
    def save(self, *args, **kwargs):
        # Set the name from the filename if not provided
        if not self.name:
            self.name = self.file.name
        # Get the file size
        self.size = self.file.size
        super().save(*args, **kwargs)
    
    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        return self.file.url
    
    def delete(self, *args, **kwargs):
        # Delete the file from storage first
        self.file.delete()
        super().delete(*args, **kwargs)

Run migrations:

python manage.py makemigrations
python manage.py migrate

Step 5: Create Forms

In files/forms.py:

from django import forms
from .models import UploadedFile

class FileUploadForm(forms.ModelForm):
    class Meta:
        model = UploadedFile
        fields = ['file']
        
    def clean_file(self):
        file = self.cleaned_data.get('file')
        if file:
            # Add any file validation here (size, type, etc.)
            if file.size > 10 * 1024 * 1024:  # 10MB limit
                raise forms.ValidationError("File too large ( > 10MB )")
        return file

Step 6: Create Views

In files/views.py:

from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, Http404
from django.conf import settings
import os
from .models import UploadedFile
from .forms import FileUploadForm

def file_list(request):
    files = UploadedFile.objects.all().order_by('-uploaded_at')
    return render(request, 'files/list.html', {'files': files})

def upload_file(request):
    if request.method == 'POST':
        form = FileUploadForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('file_list')
    else:
        form = FileUploadForm()
    return render(request, 'files/upload.html', {'form': form})

def download_file(request, pk):
    uploaded_file = get_object_or_404(UploadedFile, pk=pk)
    file_path = os.path.join(settings.MEDIA_ROOT, uploaded_file.file.name)
    
    if os.path.exists(file_path):
        with open(file_path, 'rb') as fh:
            response = HttpResponse(fh.read(), content_type="application/octet-stream")
            response['Content-Disposition'] = f'inline; filename={os.path.basename(file_path)}'
            return response
    raise Http404

def delete_file(request, pk):
    uploaded_file = get_object_or_404(UploadedFile, pk=pk)
    if request.method == 'POST':
        uploaded_file.delete()
        return redirect('file_list')
    return render(request, 'files/confirm_delete.html', {'file': uploaded_file})

Step 7: Set Up URLs

  1. In filemanager/urls.py:
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from files import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.file_list, name='file_list'),
    path('upload/', views.upload_file, name='upload_file'),
    path('download/<int:pk>/', views.download_file, name='download_file'),
    path('delete/<int:pk>/', views.delete_file, name='delete_file'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Step 8: Create Jinja Templates

Create a templates directory in your project root and add these files:

  1. templates/base.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Manager</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-4">
        <h1 class="mb-4">File Manager</h1>
        {% block content %}{% endblock %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
  1. templates/files/list.html:
{% extends "base.html" %}

{% block content %}
    <div class="mb-4">
        <a href="{{ url('upload_file') }}" class="btn btn-primary">Upload File</a>
    </div>
    
    <table class="table table-striped">
        <thead>
            <tr>
                <th>Name</th>
                <th>Size</th>
                <th>Uploaded At</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            {% for file in files %}
            <tr>
                <td>{{ file.name }}</td>
                <td>{{ (file.size / 1024)|round(2) }} KB</td>
                <td>{{ file.uploaded_at.strftime('%Y-%m-%d %H:%M') }}</td>
                <td>
                    <a href="{{ file.get_absolute_url() }}" class="btn btn-sm btn-outline-primary" target="_blank">View</a>
                    <a href="{{ url('download_file', pk=file.pk) }}" class="btn btn-sm btn-outline-success">Download</a>
                    <a href="{{ url('delete_file', pk=file.pk) }}" class="btn btn-sm btn-outline-danger">Delete</a>
                </td>
            </tr>
            {% else %}
            <tr>
                <td colspan="4" class="text-center">No files uploaded yet.</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock %}
  1. templates/files/upload.html:
{% extends "base.html" %}

{% block content %}
    <h2>Upload File</h2>
    <form method="post" enctype="multipart/form-data">
        {{ form.csrf_token }}
        <div class="mb-3">
            <label for="file" class="form-label">Select file to upload:</label>
            <input type="file" class="form-control" id="file" name="file" required>
            {% if form.file.errors %}
                <div class="text-danger">
                    {% for error in form.file.errors %}
                        {{ error }}
                    {% endfor %}
                </div>
            {% endif %}
        </div>
        <button type="submit" class="btn btn-primary">Upload</button>
        <a href="{{ url('file_list') }}" class="btn btn-secondary">Cancel</a>
    </form>
{% endblock %}
  1. templates/files/confirm_delete.html:
{% extends "base.html" %}

{% block content %}
    <h2>Confirm Delete</h2>
    <p>Are you sure you want to delete "{{ file.name }}"?</p>
    <form method="post">
        {{ form.csrf_token }}
        <button type="submit" class="btn btn-danger">Yes, delete</button>
        <a href="{{ url('file_list') }}" class="btn btn-secondary">Cancel</a>
    </form>
{% endblock %}

Step 9: Create Media Directory

Create a media directory in your project root:

mkdir media

Step 10: Run and Test

  1. Run the development server:
python manage.py runserver
  1. Visit http://localhost:8000 in your browser.

Additional Features You Might Want to Add

  1. File Type Restrictions: Modify the form to only accept certain file types.
  2. User Authentication: Associate files with users and add login requirements.
  3. File Preview: Add preview functionality for images and PDFs.
  4. Pagination: Add pagination for the file list if you expect many files.
  5. Search: Implement search functionality to find files by name.

This complete example provides all the basic functionality for file uploads, listing, downloading, and deletion in Django using Jinja templates.

Leave a Reply

Your email address will not be published. Required fields are marked *