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.

Grupowanie podprojektów w PyCharm

Niezbyt często używaną funkcją PyCharma jest jego wsparcie dla dużych projektów w postaci możliwości dodawania nowych projektów w ramach bieżącego okna. Jeszcze mniej znaną (według mnie) funkcją pozwalającą zapanować nad wieloma projektami jest możliwość grupowania projektów w strukturze drzewa.

Co warto zrobić na początku – głównie z czysto estetycznych powodów – to ustalić jakiś całkowicie oddzielny katalog, który może pozostać pusty. Ewentualnie możemy trzymać jakieś „śmieci” związane z projektem, które nie muszą być, np. pod kontrolą wersji.

Zazwyczaj podczas tworzenia nowego projektu otwieramy go w nowym oknie PyCharm – i tak też zalecałbym zrobić dla dopiero co utworzonego katalogu „głównego”. To będzie nasz punkt startowy – a PyCharm będzie nam ładnie w tytule wyświetlał nowo powstały projekt główny.

Pozostałe projekty, które chcemy mieć widoczne w PyCharmie w odpowiedniej strukturze dodawać będziemy już w taki sposób:

Przechodząc do sedna sprawy wszystko rozbija się o nazewnictwo katalogów. Jeśli uporządkujemy projekty na dysku nadając im odpowiednie człony (prefixy) rozdzielane kropką, PyCharm zatroszczy się o resztę.

Po dodaniu kolejnych projektów będą w elegancki sposób pogrupowane w paczki, jak poniżej:

Nic więcej się nie zmienia i np. nadal posiadamy udogodnienie w postaci konfigurowania środowisk Pythona dla każdego projektu indywidualnie.

Oczywiście powyższe nie dotyczy osób, które są zwolennikami trzymania w PyCharm każdego projektu oddzielnie – jak zawsze ma to swoje plusy i minusy.