Wykonanie kodu przy starcie aplikacji w Django

Wielokrotnie zdarzyło mi się (i pewnie nie tylko mi) musieć uzupełnić jakimiś wartościami bazę danych w trakcie zmian w projekcie. Chodziło konkretnie o dane, które powinny się pojawić po wdrożeniu zmian i nie powinny dawać możliwości ich zmiany bądź usunięcia ze względu na potencjalny wpływ na działanie całej aplikacji.

Pierwszy pomysł tego rozwiązania to użycie migracji, jak w poniższym przykładzie:


from django.db import migrations
from ..models import PREDEFINED_TOASTR_TYPES
def preinstall_toastr(apps, schema_editor):
ToastrType = apps.get_model('toastr', 'ToastrType')
db_alias = schema_editor.connection.alias
for title, color in PREDEFINED_TOASTR_TYPES.items():
toastr = ToastrType.objects.create(
title=title,
color=color
)
toastr.save()
class Migration(migrations.Migration):
dependencies = [
('toastr', '0001_initial'),
]
operations = [
migrations.RunPython(
migrations.RunPython.noop,
preinstall_toastr,
),
]

Po wykonaniu migracji w bazie pojawią nam się wymagane wpisy. Jednak istotnym minusem tego rozwiązania jest to, że nadal można usunąć je bezpośrednio w bazie czy nawet w panelu administracyjnym Django i nie zostaną one odtworzone.

Kolejne podejście do problemu to przeniesienie kodu odpowiedzialnego za dodawanie wpisów do bazy do pliku apps.py, który uruchamiany jest przy starcie aplikacji – czyli praktycznie zawsze po restarcie serwera. Wrzucenie kodu do metody ready pozwoli nam obejść w całkiem elegancki sposób wspomniany wcześniej problem:


from django.apps import AppConfig
class ToastrConfig(AppConfig):
name = 'toastr'
def ready(self):
from .models import ToastrType, PREDEFINED_TOASTR_TYPES
# Prevent executing before applying migrations
if is_database_synchronized(DEFAULT_DB_ALIAS):
for title, color in PREDEFINED_TOASTR_TYPES.items():
try:
ToastrType.objects.get(title=title)
except ToastrType.DoesNotExist:
new_toastr_type = ToastrType(
title=title,
color=color
)
new_toastr_type.save()

view raw

apps.py

hosted with ❤ by GitHub

Na co zwrócić musimy uwagę, w pliku __init__.py naszej aplikacji musimy jawnie wskazać ścieżkę do pliku konfiguracyjnego aplikacji, jako że plik ten jest opcjonalny:


default_app_config = 'toastr.apps.ToastrConfig'

view raw

__init__.py

hosted with ❤ by GitHub

Warto także zerknąć na kilka innych kawałków kodu, m. in. uniemożliwienie edytowania kluczowych informacji w panelu administracyjnym Django czy usuwanie tych danych. Zauważyć też można 2 drobne usprawnienia: 1) wizualna reprezentacja zapisanego koloru w panelu administracyjnym dzięki użyciu funkcji format_html oraz 2) zmiana tytułu kolumny w panelu administracyjnym poprzez właściwość short_description.

Kawałek kodu związany z synchronizacją modeli z bazą danych został zaczerpnięty ze StackOverflow, a błąd dotyczący braku synchronizacji ujawnił się dopiero przy uruchomieniu testów.

Cały kod do pobrania i przejrzenia znaleźć można na GitHub.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s

Ta witryna wykorzystuje usługę Akismet aby zredukować ilość spamu. Dowiedz się w jaki sposób dane w twoich komentarzach są przetwarzane.