How to upload and serve the videos in django

In this tutorial, we'll be building a video uploading and serving web application using the django framework. So without wasting any time let's get started!

Setting up the new project

Let's start by creating a fresh virtual envioronment for our project. Just open your terminal type the following commands.

python -m venv env
env\Scripts\Activate
If you'r using a linux machine then type the below command to activate your virtual environment.
source ./env/bin/activate

Let's move on to installing django into our virtual environment then creating a new django project and our main 'core' app.

pip install django
django-admin startproject vidupload
cd vidupload

python manage.py startapp core

Configure Settings

To let django know about our new app add the 'core' to INSTALLED_APPS list inside the project's settings.py file.

vidupload/settings.py
INSTALLED_APPS = [
    ...
    'core',
]

In order to support video uploading and accessing functionality we also need to specify 'MEDIA_ROOT' and 'MEDIA_URL' settings.

vidupload/settings.py
MEDIA_URL ='/media/'
MEDIA_ROOT = Path.joinpath(BASE_DIR,"media")

We also have to configure urls.py

vidupload/urls.py
from django.contrib import admin
from django.urls import path, include

from django.conf.urls.static import static
from django.conf import  settings


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('core.urls')),
]

urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

Create a new core/urls.py file and keep the urls related to core app inside it.

core/urls.py
from django.urls import path
from core import views

app_name='core'

urlpatterns = [
]

Create Models and Forms

Its time to create the main 'Video' database model of our project.

core/models.py
from django.db import models
from django.core.validators import FileExtensionValidator

class Video(models.Model):
    title = models.CharField(max_length=30)
    video = models.FileField(upload_to='media/videos/',
                            validators=[FileExtensionValidator( ['mp4'] ) ]
                            )
    uploaded_on = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

Here I've created three fields the title field(The Title of the video), video(The actual video) and uploaded_on(Date Time of video upload)

Note: Here i have used FileExtensionValidator validator inside the video field to restrict the users to only upload the .mp4 files. Also later in the tutorial we'll see how to set the max size limit for video uploading.

Now in order to accept user input from the frontend. Let's create modelform for our Video model.

Create a new core/forms.py
from django import forms
from core.models import Video

class VideoForm(forms.ModelForm):
    class Meta:
        model=Video
        fields="__all__"

Add the following code to register the Video model to the django admin console.

core/admin.py
from django.contrib import admin
from core.models import Video

admin.site.register(Video)

Its time to make migrations for our project models and migrate them to the database. Just copy and paste the below commands to the terminal.

python manage.py makemigrations
python manage.py migrate

Views And Templates

Its time to write the business logic of our video uploading application i.e views. but first of all we need to add the necessary url endpoints in core/urls.py.
core/urls.py
urlpatterns = [
    path('', views.upload, name='upload'),
    path('latest-videos/', views.latest_videos, name='latest_videos'),
]
core/views.py
from django.shortcuts import render, redirect

from core.forms import VideoForm
from core.models import Video

def upload(request):
    if request.method=='POST':
        form = VideoForm(request.POST, request.FILES)

        if form.is_valid():
            form.save()
            return redirect("core:latest_videos")
    else:
        form = VideoForm()
    return render(request, "upload.html", {"form": form})

Here the 'upload' function that takes http request as the first argument will be responsible to handle the logic of video uploading functionality of our application.

Now let's write the 'latest_videos' view function to display the latest 5 videos.

core/views.py
def latest_videos(request):
    # Fetch the latest 5 videos
    videos = Video.objects.all().order_by("-uploaded_on")[0:5]
    return render(request, "latest_videos.html"
                    , {'videos': videos})

Now, Let's create the frontend html templates to let users upload and see videos in our application. To do so create a new directory named 'templates' inside the core app and create two html template files 'upload.html' and 'latest_videos.html' and paste the below code.

core/templates/upload.html
<form enctype="multipart/form-data" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit">
</form>
core/templates/latest_videos.html
<h1>Latest 5 videos</h1>
{% for video in videos %}
    <div>
        <h1>{{ video.title }}</h1>
        <h3>{{ video.uploaded_on }}</h3>
        <video controls style="width: 280px;">
            <source type="video/mp4" src="{{video.video.url}}">
        </video>
    </div>
{% endfor %}

Finaly, It's time to spin up our django development server and see if everything is working fine.

python manage.py runserver

Head over to http://127.0.0.1:8000/ and try to upload some videos. Then you should be able to see something like this.

Upload Video Form Video uploaded output

Set the max upload size limit

Another common requirement for the application like this would be to impose the max size limit to the each video upload. To do so we need to create a custom validator function and it inside the 'video' field in our model. Here is the code for that.

core/models.py
        
...
from django.core.exceptions import ValidationError

def file_size(value):
    '''
    Custom validator to limit the file size
    '''
    # For demo we are setting the limit to 5mb
    limit = 5 * 1024 * 1024
    # Check the file size and raise the validation error if its more than 5mb.
    if value.size > limit:
        raise ValidationError('File too large. Size should not exceed 5 MB.')

class Video(models.Model):
    ...
    video = models.FileField(upload_to='media/videos/',
                            validators=[FileExtensionValidator( ['mp4'] ), file_size ]
                            )
    ...

        
    

Here we created the 'file_size' validator that raises ValidationError if size is greater than 5mb. Then we add it inside the validators list of the 'video' field.