1

In my project, I have a main static folder and a sub folder named static. When I make changes in my sub folder named static (which I specified in COLLECTSTATIC_DIRS within the settings file), I save the file and run the collectstatic command.

This successfully saves the changes, however is really inefficient as I am constantly changing css and Javascript files inside my project, which I store as static files.

I browsed the web, and came across a solution named whitenoise, which is a pip package. But this package only works for a short period of time, and after a few times of closing and opening my project folder, it completely stopped working.

Does anybody have another solution to deal with this problem? Thank you.

NodeReact020
  • 486
  • 5
  • 23

4 Answers4

1

You can use python-watchdog and write your own Django command:

import time

from django.conf import settings
from django.core.management import call_command
from django.core.management.base import BaseCommand
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer


class Command(BaseCommand):
    help = "Automatically calls collectstatic when the staticfiles get modified."

    def handle(self, *args, **options):
        event_handler = CollectstaticEventHandler()
        observer = Observer()
        for path in settings.STATICFILES_DIRS:
            observer.schedule(event_handler, path, recursive=True)
        observer.start()
        try:
            while True:
                time.sleep(1)
        finally:
            observer.stop()
            observer.join()


class CollectstaticEventHandler(FileSystemEventHandler):
    def on_moved(self, event):
        super().on_moved(event)
        self._collectstatic()

    def on_created(self, event):
        super().on_created(event)
        self._collectstatic()

    def on_deleted(self, event):
        super().on_deleted(event)
        self._collectstatic()

    def on_modified(self, event):
        super().on_modified(event)
        self._collectstatic()

    def _collectstatic(self):
        call_command("collectstatic", interactive=False)
adonig
  • 189
  • 2
  • 9
1

Here's an example using Python watchfiles and a Django management command.

# Lives in /my_app/manangement/commands/watch_files.py
import time

from django.conf import settings
from django.core.management import call_command
from django.core.management.base import BaseCommand

from watchfiles import watch


class Command(BaseCommand):
    help = "Automatically calls collectstatic when the staticfiles get modified."

    def handle(self, *args, **options):
        print('WATCH_STATIC: Static file watchdog started.')
        #for changes in watch([str(x) for x in settings.STATICFILES_DIRS]):
        for changes in watch(*settings.STATICFILES_DIRS):
            print(f'WATCH_STATIC: {changes}', end='')
            call_command("collectstatic", interactive=False)

You can then run the Django management command in the background in whatever script you use to start Django.

python manage.py watch_static &
python manage.py runserver 0.0.0.0:8000
0

You can use 3rd party solution which doesn't belong to Django to monitor your files and run commands on the files changes.

Take a look at fswatch utility Bash Script - fswatch trigger bash function

How to manage static files "Django-way"

Please check details on https://docs.djangoproject.com/en/3.0/howto/static-files/ what is a Django-way to do it correct :)

Alexandr Shurigin
  • 3,921
  • 1
  • 13
  • 25
  • Is there no pip package belonging to Django that solves this problem though? – NodeReact020 Dec 14 '19 at 23:37
  • not, because normally nobody re-runs `collecstatic` command on files changes :) That is a command which you should run in production environment only once when you are deploying new source code release. Django embedded dev webserver has ability to server staticfiles right from their apps without collecting it – Alexandr Shurigin Dec 14 '19 at 23:38
  • Ah, so how do you use this functionality embedded in django's dev web server? Do you have to do anything in settings file, or anything special at all to use this functionality? Also, do you not provide STATICFILES_DIR in settings.py? – NodeReact020 Dec 14 '19 at 23:47
  • updated my answer with some more details. please check it – Alexandr Shurigin Dec 14 '19 at 23:48
0

First of all set DEBUG = True while working on development.

Then add these lines to your project's urls.py:

from django.conf import settings
from django.views.decorators.cache import cache_control
from django.contrib.staticfiles.views import serve
from django.conf.urls.static import static

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL,
                      view=cache_control(no_cache=True, must_revalidate=True)(serve))
engin_ipek
  • 887
  • 1
  • 8
  • 10