Django FileField – Everything You Need to Know

In this blog, the goal is to show the capabilities of Django’s built-in Fields, specifically Django FileField, for storing files. Every experienced web developer had to work with files at one point. Files can be stored in a database in many ways, either locally or on a server.

So what actually is FileField in Django?

Django FileField inherits an abstract Field class representing the database table column, and it is used for simple file uploads.

Before we go into a more detailed explanation of the FileField parameters, we will define one model with a pdf_file column.

class Book(models.Model):
   title = models.CharField(max_length=255)
   published_date = models.DateTimeField(null=True)

   pdf_file = models.FileField()

Let’s look at how FileField behaves in the database and what we use it for.

Django FileField in Database

For the specified model after python manage.py makemigrations the following migration file is obtained.

class Migration(migrations.Migration):

   initial = True

   dependencies = [
   ]

   operations = [
       migrations.CreateModel(
           name='Book',
           fields=[
               ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
               ('title', models.CharField(max_length=255)),
               ('published_date', models.DateTimeField(null=True)),
               ('pdf_file', models.FileField(upload_to='')),
           ],
       ),
   ]

And after migrating python manage.py migrate we get the following data structure in the database:

NameData TypeDatabase Example
idBig int2
titleCharacter Varying (255)Django FileField Book
published_dateTimestamp with time zone2022-01-19 16:56:03+01
pdf_fileCharacter Varying (100)django_filefield_book.pdf

We see one interesting thing, FileField is stored in the Postgres database as Character Varying.

What would that mean for our files? Where do they end up?

Our files are stored locally on the computer. So in this example, the FileField or pdf_file column in the database would save the path of our file.

Let’s look at the FileField parameters.

Django FileField parameters

class FileField(upload_to=None, max_length=100, **options)

FileField has 2 optional parameters. Let’s see in the following example what these parameters actually mean.

pdf_file = models.FileField(upload_to='uploads/', max_length=255, **options)

  • upload_to specifies the route to which a particular file will be saved. For example, book.pdf will be saved in the BASE_DIR/uploads directory, the file name and folder in which the file is located will be saved in the database.
  • max_length determines the maximum length of the saved path. The default is 100. If you have files and paths with long names, you must not forget to change this parameter. Otherwise, you might get DatabaseError: value too long for type character varying (100).

Finally, let’s look at an example of a saved book in the database:

idtitlepublished_datepdf_file
1Book2022-01-19 19:49:22+01uploads/book.pdf

Although we have defined the directory in which we save the files, it is still not the best practice.
According to the official Django documentation, the files should be saved in the MEDIA folder. The media folder should be defined in the Django settings, so let’s show what it should look like.

Define next in your settings.py.

MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 
MEDIA_URL = '/media/'

From the moment we define MEDIA_ROOT, all subsequent files we upload will be saved in media/uploads/ because we defined upload_to = 'uploads'. But only the file path upload_to + file_name is saved in the database.

Now that we have successfully saved our files to the computer. How can we retrieve these files?

How to access FileField files?

We access our files via URL with the exposed path to the file.
So let’s try to access our file saved in media/uploads/book.pdf

We simply send a GET request to http://127.0.0.1:8000/media/uploads/book.pdf, but we get: Not Found: /media/uploads/book.pdf

More precisely: "GET /media/uploads/book.pdf HTTP/1.1" 404

So why is that so?
This happens because the path is not defined in urls.py, i.e., Django tries to find a valid path to the file we are looking for, but as it does not find the right URL, it concludes that it does not exist.


So the next step is to define a valid URL, but since files can be named differently, how do we do that?

It is quite simple, we previously defined the MEDIA folder, and it now stores files. We just have to expose that file in URLs, so we can then access everything in it in the following way: host + media_root + upload_to parameter (what is saved in the database as varchar)

Let’s see how to expose a URL. Set the following in root URLs:

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

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
WARNING - use this only in Development! This method of serving static files is NOT safe in production. Read more in the official Django documentation

Now that we’ve exposed the files, we can finally retrieve the file via URL. Assuming you’re running this locally, let’s type the following:

http://127.0.0.1:8000/ + media/ + upload_to parameter

In this example, considering upload_to parameter is uploads/book.pdf:

http://127.0.0.1:8000/media/uploads/book.pdf

The uploaded pdf is displayed in the web browser, and we get:
"GET /media/uploads/book.pdf HTTP / 1.1" 200

NOTE - Occasionally we can get a response with status code 304. No need to worry, it's a redirection to a cached resource.

FileField with Django ORM

Object-relational mapping helps us create queries over the database without writing actual SQL queries. So it can be pretty handy.

In the following example, we will show what can be done with Django ORM.

# Filters books using string manipulation of pdf_file
Book.objects.filter(pdf_file__exact='uploads/book.pdf')
Book.objects.filter(pdf_file__iexact='uploads/BOOK.pdf')
Book.objects.filter(pdf_file__contains='book')
Book.objects.filter(pdf_file__endswith=".pdf")
Book.objects.filter(pdf_file__startswith="uploads")
    
# Filters books using regex
Book.objects.filter(pdf_file__regex='book')
    
# Filters books by existing pdf_file
Book.objects.filter(pdf_file__isnull=False)
    
# Filters books by given array of pdf_files
Book.objects.filter(pdf_file__in=['uploads/book.pdf'])

As we can see, since pdf_column is character varying in the database, we can do all the standard operations on it, which we could do with CharField, for example. Here are just a few, mostly retrieving books using string operations.

Summary

FileField is a powerful tool for saving files. However, it is also dangerous to misuse and expose files that we should not reveal. Now you can use everything you learned and finally start uploading files to your application.

I hope you found this blog post helpful!