Manage Static Files in Django

Posted in /  

Manage Static Files in Django
vinaykhatri

Vinay Khatri
Last updated on April 19, 2024

    A web page also contains static assets like CSS, JavaScript, and images. And Django provides a specific configuration and storage pattern for such files. Django comes with an inbuilt app “staticfiles” that manage all the static files for the project. To distinguish the static files, Django also provides a special configuration to handle staticfiles for development and deployment purposes.

    In this article, we will discuss how to deal with static files in Django and learn how to serve static files in a project with debug modes True and False.

    Create Django Project

    So let’s get started with creating a Django project.

    To create a Django project, we use the django-admin startproject <project_name> command.

    django-admin startproject static_tutorial

    The above command will create a Django project with the name static_tutorial, if Django is installed for your python environment.

    static_tutorial
      manage.py
      db.sqlite3
      static_tutorial
            asgi.py
            settings.py
            urls.py
            wsgi.py
            __init__.py

    It’s time to change the directory to static_tutorial project and run the local server.

    python manage.py runserver

    After running the local server, open localhost:8000 on the browser, and you will see the default app page of Django.

    Handling Static files in Django

    Django provides a specific setting to manage and handle static files. And to manage all static files, we need to configure the settings.py file.

    Step 1: Configure Static URL

    The first thing we need to configure is defining the STATIC_URL path for the static files in static_tutorial/setting.py file. The STATIC_URL is reserved identifiers in the Django setting.py file that defines the URL path for all the static files present in the project.

    # static_tutorial/setting.py
    STATIC_URL = '/static/'

    Note 1: The name static is arbitrary. It could be anything, but the name must include ‘ / ’ at the end of the name. Note 2: In your Django project, the STATIC_URL will come predefined, you can change the value to any arbitrary name if you want, but we suggest you leave it as it is.

    Step 2: Configure STATICFILES_DIRS

    The STATICFILES_DIRS is also a reserved identifier that represents a list of static files, folders, or directories located in the local development environment. A project can have multiple apps, and each app can have its own static file directory. That's why we define an identifier STATICFILES_DIRS that contains the path for all the static files present in the project.

    For our project, we are defining a single static file directory at the top level of our project with the name static , that's why we will only define a single path in the STAITCFILES_DIRS list.

    #static_tutorial/settings.py
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [BASE_DIR / 'static', ]      #new

    Step 3: Configure STATIC_ROOT

    STATIC_ROOT identifier is for the production level. It defines a directory that will collect all the static files when the project when the collectstatic command is executed. In STATIC_ROOT, we define a directory path that will contain all the static files during deployment.

    With STATIC_ROOT , we distinguish the static files of deployment level to deployment level. As the STATIC_ROOT defines the location of static files for deployment or project, its name must also be different from the static files directories defined in the STATICFILES_DIRS list.

    STATIC_URL = '/static/'
    STATICFILES_DIRS = [BASE_DIR / 'static', ] 
    
    STATIC_ROOT = BASE_DIR / 'staticfiles'     #new

    STEP4: Check the 'django.contrib.staticfiles' in INSTALLED_APPS

    Django comes with many installed apps that are listed in settings.py as INSTALLED_APPS . There only Django provides an installed app 'django.contrib.staticfiles' that is responsible for handling static files in a Django project.

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]

    Static Directory

    Now we are done with settings.py file for static configuration, let's create a static directory in the root project directory where our manage.py is located. To create the directory, we can use the mkdir command

    mkdir static 
    mkdir static/css
    mkdir static/img

    The above commands will create a static directory in the root folder and css , & img as the static subdirectories.

    static_tutorial:
        db.sqlite3
        manage.py
     
        static
            css
            img
        static_tutorial
            asgi.py
            settings.py
            urls.py
            wsgi.py
            __init__.py

    We have already configured Django, which directory to look for the static files, with the STATICFILES_DIRS identifier in the setting.py file.

    Inside the static directory, we have also created two subdirectories css and img , that will contain CSS and image files, respectively. This makes the code modular and easy to maintain.   In the css directory let's create a style.css file that will style our web page.

     
     /* static/css/style.css */
    body
    {
        background-color: black;
        color: white;
    }
     

    And in the img directory, store a feature.png image.

    static
        css
           style.css
        img
           feature.jpg

    Load Static file in a Template directory

    The static files are loaded in an HTML template. The web page that we see on our browser is an HTML page with loaded CSS, images, and JavaScript. And Django defines a different configuration to handle template files like HTML and XML.

    Similar to static file management, we need to configure the template directory in the settings.py file and create a template directory in the root folder of our project where the manage.py file is located.

     
    #static_tutorial/setting.py
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
    
            'DIRS': [BASE_DIR / 'templates'],  #new
    
            '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',
                ],
            },
        },
    ]
     

    In the above code, we specify the location where Django looks for the custom templates. The BASE_DIR / 'templates' define the templates directory in the project root directory where the manage.py file is located.

    Create templates directory

    After specifying the template's directory location, let's create the template's directory and an index.html file in it.

    mkdir templates 
    echo > templates\index.html

    The above two commands will create a new directory template and the index.html file in the templates directory, respectively. The above echo command will only work for windows, If you are on a mac or Linux, use the touch command. Example (mac/Linux) touch templates\index.html

    templates
          index.html

    Now let's write the index.html file and load the static files style.css and feature.png image in it using the template tags.

    <!-- templates/index.html -->
    {% load static %}
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Tutorial</title>
    <!-- CSS -->
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    
    </head>
    <body>
        <center>
            <h1>Heading</h1>
            <img src="{% static 'img/feature.png'%}">
        </center>
    
    </body>
    </html>

    {%load static%}

    The {%load static%} is a template tag that needs to be written at the top of the HTML script, and it loads the static files in an HTML template file. If we forget to write {%load static%} in our HTML file and use the {%static%} tag, we will encounter the error Invalid block tag on line : 'static'. Did you forget to register or load this tag?

    {%static%}

    The {%static%} tag is defined in the under django.contrib.staticfiles app. This tag is used to import the specific static file in the HTML file. In the above example, we have used this tag to load the style.css and feature.png images in the index.html.

    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    <img src="{% static 'img/feature.png'%}">

    Set views.py and urls.py file

    As we have not created any app in this project to render the index.html page, we can create a views.py file in the static_tutorial directory where the settings.py file is located. for windows.

    cd static_tutorial
    echo > views.py 

    views.py

    from django.shortcuts import render
    
    def homepage(request):
        return render(request, 'index.html')

    urls.py

    from django.contrib import admin
    from django.urls import path
    from .views import homepage
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', homepage, name='index')
    ]

    Now run the local server with python manage.py runserver
    python manage.py runserver
    And if you inspect the image and the CSS imported in the HTML file, they all have a URL as /static/css/ and /static/img/ that we have defined in the STATIC_URL .

    Serve Django Static File with Debug = False

    Django is not built for serving static files. Django suggest a separate server or S3 buckets serve file if the project is in production and when debug mode is off Debug=False .
    If we set the debug mode off in the setting.py file and run or reload the server again. All the static files will not be loaded on the page.
    DEBUG = False
    
    ALLOWED_HOSTS = ['*']

    When we set Debug=False we also need to set the ALLOWED_HOSTS value to the server that is hosting the project. The asterisk * means all. In such cases, when Debug mode is False, and you do not want to use any other server or S3 bucket to load the static files, there you can use the whitenoise library that can serve the static file. Using this library is very easy all we need to do is install it for our Python environment and add it to the middleware list in the setting.py file.

    Whitenoise library

    With whitenoise and configuring the setting.py file, we can serve the static files in Django without relying on the server like Nginx and Amazon S3 bucket. Many hosting providers like Heroku. OpenShift encourages the use of the whitenoise library for static files. To install whitenoise for your python environment, run the following pip install command .

    pip install whitenoise

    After installing the whitenoise library, we need to add its middleware in the settings.py file.

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
    
         'whitenoise.middleware.WhiteNoiseMiddleware',   #new
        
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    This is not it when we set the Debug to False; this means we are using the production settings in that case, Django does not use the development static file directory. Instead, it uses the STATC_ROOT directory. In the above section, we have already defined the SATIC_ROOT to 'staticfiles'.

    Now, the whitenoise will search for the staticfiles directory for all static files. The next command we need to run is python manage.py collectstatic. It will collect all the static files that are present in the STATICFILES_DIRS and all the other inbuilt and third-party libraries static into the directory staticfiles directory.

    python manage.py collectstatic

    The above command will create a directory by the name staticfiles in the project root directory.

        staticfiles
            admin
            css
                vendor
            select2
            fonts
            img
            gis
            js
            admin
                vendor
                jquery
                select2
                i18n
                xregexp
                css
                img

    Now, if we run the server again Django will load the CSS and image in our HTML file.

    Conclusion

    Django has some predefined identifiers and settings to manage static files. Some of the most important identifiers are STATIC_URL, STATICFILES_DIRS, and STATIC_ROOT, which represent the URL path, local static directories, and production static directory path. Django is not built to serve static files at the production level. It always suggests using a separate server or S3 buckets for static files. But with third-party libraries like whitenoise, we can serve static files without using any other service.

    People are also reading:

    Leave a Comment on this Post

    0 Comments