"""
:file:`apps.py` ::
from django import apps
from django.utils.translation import gettext_lazy as _
from . import signals
__all__ = ('MyApp', )
class MyAppConfig(apps.AppConfig):
name = 'myapp'
verbose_name = _('My Application')
def ready(self):
signals.connect(self)
:file:`signals.py` ::
from django.db.models import signals as dj_signals
from django.db.backends import signals as dj_db_signals
from pytoolbox.django.signals import (
create_site, setup_postgresql_hstore_extension, strip_strings_and_validate_model
)
# ...
def connect(config):
'''Connect signal handlers to signals.'''
dj_db_signals.connection_created.connect(setup_postgresql_hstore_extension)
dj_signals.post_migrate.connect(create_site, sender=config)
dj_signals.pre_save.connect(
strip_strings_and_validate_model, sender=settings.AUTH_USER_MODEL)
"""
import logging
from django.conf import settings
from django.db.models import fields
from django.db.models.fields.files import FileField
__all__ = [
'logger',
'clean_files_delete_handler',
'create_site',
'setup_postgresql_hstore_extension',
'strip_strings_and_validate_model'
]
logger = logging.getLogger(__name__)
[docs]def clean_files_delete_handler(instance, signal, **kwargs):
"""
Remove the files of the instance's file fields when it is removed from the database.
Simply use ``post_delete.connect(clean_files_delete_handler, sender=<your_model_class>)``
.. warning::
This function remove the file without worrying about any other instance using this file !
.. note::
Project `django-cleanup <https://github.com/un1t/django-cleanup>`_
is a more complete alternative.
"""
for field in kwargs['sender']._meta.fields:
if isinstance(field, FileField):
file_field = getattr(instance, field.name)
if file_field.path:
file_field.delete(save=False)
[docs]def create_site(sender, **kwargs):
"""
Ensure the site name and domain is well configured.
Some alternative:
* Loading an initial fixture with the values for the site
* The application `django-defaultsite <https://github.com/oppian/django-defaultsite>`_
* Other options discussed here:
`here <https://groups.google.com/forum/#!topic/django-developers/X-ef0C0V8Rk>`_
"""
from django.contrib.sites import models as site_app
site_fields = {'domain': settings.SITE_DOMAIN, 'name': settings.SITE_NAME}
site = site_app.Site.objects.update_or_create(pk=settings.SITE_ID, defaults=site_fields)[0]
logger.info(
f'Updated settings of Site "{site.name}" with ID {site.pk} and domain {site.domain}')
[docs]def setup_postgresql_hstore_extension(sender, connection, **kwargs):
from psycopg2.extras import register_hstore
cursor = connection.connection.cursor()
cursor.execute('CREATE EXTENSION IF NOT EXISTS hstore')
register_hstore(connection.connection, globally=True)
[docs]def strip_strings_and_validate_model(sender, instance, raw, **kwargs):
"""Strip the string fields of the instance and run the instance's full_clean()."""
if not raw:
logger.debug(f'Validate model {instance} on save() with kwargs={kwargs}')
for field in instance._meta.fields:
if isinstance(field, (fields.CharField, fields.TextField)):
field_value = getattr(instance, field.name)
if isinstance(field_value, str):
setattr(instance, field.name, field_value.strip())
instance.full_clean()