I have dockerized Django application. When I press save in any file, the server is restarted and docker image rebuild.
I would like similar functionality: Whenever I press save in any file, I would like that my function is called after server is rebooted.
How to achieve this behaviour.
I try with overriding FileSystemStorage
but it's not working.
from django.core.files.storage import FileSystemStorage
class CustomFileSystemStorage(FileSystemStorage):
def _save(self, name, content):
saved_file_name = super()._save(name, content)
self.my_custom_function(saved_file_name, name, content)
return saved_file_name
def my_custom_function(self, file_path, name, content):
print('File saved at: ', file_path)
print('File name: ', name)
print('File content: ', content)
settings.py
:
DEFAULT_FILE_STORAGE = 'myApp.storage.CustomFileSystemStorage'
When I save file nothing is logged
By press save on ant file
I mean press cmd+s
on a file that I was editing (for example: test.py
)
Any change on disk results in rebuilding the docker image. I would like to do similar that they did.
I thought that because on save server is restarted and docker image rebuild... maybe there is a way to tap on those triggers.
Can I trigger my function when server is restarted? But there would probably be difficult to get a file that was changed...
My apps.py
from django.apps import AppConfig
import logging
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myApp'
def ready(self):
logger = logging.getLogger(__name__)
logger.info("READY 123123")
I also try
from django.apps import AppConfig
import logging
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myApp'
def ready(self):
print('TEST')
The settings.py
"""
Django settings for WisdomCore project.
Generated by 'django-admin startproject' using Django 4.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'xxx'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'my_app'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'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',
]
ROOT_URLCONF = 'Projects.urls'
TEMPLATES = [
{
'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',
],
},
},
]
WSGI_APPLICATION = 'Project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django': {
'level': 'INFO',
'handlers': ['console'],
'propagate': True,
},
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
}
},
}
The logs are:
I don't have any other code...
My tree
├── Dockerfile
├── Project
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── docker-compose.yml
├── my_app
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── install.sh
├── local_settings.py
├── makefile
├── manage.py
├── neo4j-conf
│ └── neo4j.conf
├── neo4j_data
└── requirements.txt
Thank you all for the great suggestions that lead me to the correct answer.
Similar to @Daviid suggestion, I solve this by AppConfig
Create a management command that contains the code you would like to run
# commands/startup_actions.py
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Actions to perform on server startup or app ready'
def handle(self, *args, **options):
# Put your startup actions here, similar to what you would have done in AppConfig.ready
print("Server is starting up or app is ready.")
Call this method inside AppConfig:
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myApp'
def ready(self):
# Run the custom management command on server startup
from django.core.management import call_command
call_command('startup_actions')
This actually works and prints "Server is starting up or app is ready." on file save.
You can use the watchdog library to detect which file has been changed
Pip install watchdog:
pip install watchdog==3.0.0
also put it inside requirement.txt
Create a file_observer.py
file on the root
directory
# file_observer.py
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler, RegexMatchingEventHandler
from graph_parser.parser import CypherMethodParser
class MyHandler(RegexMatchingEventHandler):
def on_modified(self, event):
if event.is_directory:
return
# This function will be called when a file is modified
print(f"File {event.src_path} has been modified with {event} event.")
# Sometimes this is called 2 times in a row. To prevent this put sleep
time.sleep(1)
def start_observer():
event_handler = MyHandler(regexes=[r'.*\.py$', r'.*\.csv$'])
observer = Observer()
observer.schedule(event_handler, path='.', recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
if __name__ == "__main__":
start_observer()
Inside the install.sh
(or where you install requirements.txt in your docker container...) add
pip install --upgrade pip
pip install -r requirements.txt
python file_observer.py & # <--- this is the new line