Witajcie!
Pracując ze społecznością PyMasters spotkałem się z ciekawymi opiniami na temat migracji. Chyba najbardziej zaskoczyło mnie to, że ludzie nie trzymają migracji w repozytorium. Nawet zaawansowani programiści. Zauważyłem też, że migracje sprawiają sporo problemów osobom początkującym. To właśnie była inspiracja do napisania tego posta - stworzyć kompletny poradnik działania migracji, od podstaw do eksperta.
Ten post będzie podzielony na dwie części, gdyż materiał jest bardzo obszerny.
W pierwszej części omówię:
- Czym są migracje w Django i ich historia
- Jak działają migracje w Django na przykładzie modelu produktu w sklepie internetowym
- Wehikuł czasu - migracje wstecz i backupy bazy danych w Django
- Jak robić migracje danych w Django
A w następnym poście pokażę:
- Jak dodać pole z unikalną zawartością, gdy już mamy dane w bazie?
- Jak rozwiązywać konflikty w migracjach?
- Jak, dzięki automatyzacji, nie zapomnieć dodać migracji do projektu
- Najpopularniejsze błędy migracji w Django i jak je rozwiązać
- Bonus: Czym jest
--fakew migracjach Django?
Zatem do dzieła!
Czym są migracje w Django i ich historia
Wprowadzenie do migracji
Migracje w Django są mechanizmem, który pozwala na zarządzanie zmianami w strukturze bazy danych w sposób zautomatyzowany i kontrolowany. Umożliwiają one synchronizację schematu bazy danych z definicjami modeli w kodzie aplikacji, co jest kluczowe dla utrzymania spójności danych oraz unikania błędów związanych z ręczną aktualizacją schematu bazy danych.
Migracje są generowane automatycznie na podstawie zmian wprowadzonych w modelach. Oznacza to, że każda zmiana w strukturze modelu, taka jak dodanie nowego pola, zmiana typu danych czy usunięcie kolumny, może zostać automatycznie wykryta i zapisana w formie migracji. Dzięki temu cały zespół deweloperski może pracować na tej samej wersji schematu bazy danych, co znacznie ułatwia współpracę i minimalizuje ryzyko konfliktów oraz błędów.
Ważnym aspektem pracy z migracjami jest konieczność dodawania plików migracji do systemu kontroli wersji, np. Git. Dzięki temu zmiany w strukturze bazy danych mogą być śledzone, wersjonowane i łatwo współdzielone między członkami zespołu. Zapis w systemie kontroli wersji jest również konieczny, by bezpiecznie publikować zmiany aplikacji na serwerach produkcyjnych.
Zalety migracji w Django
- Automatyzacja procesu: Migracje są generowane automatycznie na podstawie modeli, co eliminuje potrzebę ręcznego pisania skryptów SQL i zmniejsza ryzyko błędów.
- Współpraca zespołu: Dzięki migracjom wszyscy członkowie zespołu deweloperskiego mogą pracować na tej samej wersji schematu bazy danych, co ułatwia synchronizację pracy i zarządzanie zmianami.
- Historia zmian: Migracje pozwalają na śledzenie historii zmian w bazie danych, co umożliwia łatwe prześledzenie i zrozumienie ewolucji schematu bazy danych.
- Bezpieczeństwo aktualizacji: Migracje umożliwiają testowanie zmian w lokalnym środowisku przed wdrożeniem ich na produkcję, co minimalizuje ryzyko błędów i nieprzewidzianych problemów.
- Elastyczność: Migracje wspierają zarówno migracje w przód (wprowadzanie zmian), jak i w tył (wycofywanie zmian), co pozwala na łatwe cofnięcie niechcianych zmian w bazie danych.
Historia migracji w Django
Początkowo, w pierwszych wersjach Django, narzędzie do zarządzania migracjami nie było wbudowane w framework. W tym czasie popularnym narzędziem do migracji była aplikacja South, która była niezależnym projektem rozwijanym przez społeczność.
Etapy rozwoju migracji w Django:
- Początki: South -
Southbył narzędziem, które wprowadziło pojęcie migracji do ekosystemu Django. Umożliwiał zarządzanie schematem bazy danych w sposób zautomatyzowany, jednak wymagał dodatkowej konfiguracji i instalacji (tak, byłem tam!). - Wersja Django 1.7 - Migracje stały się natywną częścią Django od wersji 1.7. Wprowadzenie wbudowanego systemu migracji było krokiem milowym, który ujednolicił i uprościł zarządzanie bazą danych.
- Dalszy rozwój - Od wersji 1.7, system migracji był stale rozwijany i udoskonalany. Wprowadzono nowe funkcje, takie jak obsługa migracji danych, co umożliwiło jeszcze lepsze zarządzanie zmianami w bazie danych.
Jak działają migracje w Django na przykładzie modelu produktu w sklepie internetowym
Aby lepiej zrozumieć, jak działają migracje, przejdźmy przez przykład modelu produktu w sklepie internetowym. W tym przykładzie wykonamy kilka typowych operacji: dodanie nowego pola, modyfikację istniejącego pola i usunięcie pola.
Krok 1: Tworzenie początkowego modelu
Na początku tworzymy prosty model produktu:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField()
def __str__(self):
return self.nameNastępnie tworzymy migrację i stosujemy ją:
python manage.py makemigrations
python manage.py migratePierwsza migracja tworzy tabelę Product w bazie danych. Polecenie makemigrations tworzy plik z migracją, który musimy dodać do systemu kontroli wersji. Dopiero migrate wykonuje operacje na bazie danych.
Zawartość pliku migracji 0001_initial.py:
# 0001_initial.py
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Product',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('price', models.DecimalField(max_digits=10, decimal_places=2)),
('description', models.TextField()),
],
),
]Krok 2: Dodanie nowego pola
Dodajemy nowe pole stock, które będzie przechowywać informację o dostępnej ilości produktu:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField()
stock = models.PositiveIntegerField(default=0) # nowe pole
def __str__(self):
return self.nameTworzymy nową migrację:
python manage.py makemigrations
python manage.py migrateZawartość pliku migracji 0002_add_stock_to_product.py:
# 0002_add_stock_to_product.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shop', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='product',
name='stock',
field=models.PositiveIntegerField(default=0),
),
]Krok 3: Modyfikacja istniejącego pola
Modyfikujemy pole description, aby było opcjonalne:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField(null=True, blank=True) # zmiana pola
stock = models.PositiveIntegerField(default=0)
def __str__(self):
return self.nameTworzymy nową migrację:
python manage.py makemigrations
python manage.py migrateZawartość pliku migracji 0003_alter_description_in_product.py:
# 0003_alter_description_in_product.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shop', '0002_add_stock_to_product'),
]
operations = [
migrations.AlterField(
model_name='product',
name='description',
field=models.TextField(null=True, blank=True),
),
]Krok 4: Usunięcie pola
Usuwamy pole stock, aby uprościć nasz model:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField(null=True, blank=True)
def __str__(self):
return self.nameTworzymy nową migrację:
python manage.py makemigrations
python manage.py migrateZawartość pliku migracji 0004_remove_stock_from_product.py:
# 0004_remove_stock_from_product.py
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('shop', '0003_alter_description_in_product'),
]
operations = [
migrations.RemoveField(
model_name='product',
name='stock',
),
]Omówienie zawartości pliku migracji
Każdy plik migracji w Django składa się z kilku kluczowych elementów:
- dependencies: Lista zależności określająca, które migracje muszą być wykonane wcześniej. Pozwala to na zachowanie kolejności wykonywania migracji.
- operations: Lista operacji, które mają zostać wykonane w tej migracji. Operacje mogą obejmować dodawanie pól (AddField), modyfikację pól (AlterField), usuwanie pól (RemoveField), a także inne zmiany struktury bazy danych.
Przykład operacji:
- AddField: Dodaje nowe pole do istniejącego modelu. W naszym przypadku, pole
stockjest dodawane do modeluProduct. - AlterField: Modyfikuje istniejące pole w modelu. Pole
descriptionzostało zmienione, aby było opcjonalne. - RemoveField: Usuwa pole z modelu. Pole
stockzostało usunięte z modeluProduct.
Każda operacja jest zapisana jako metoda w klasie migrations.Migration, co umożliwia Django zarządzanie i wykonywanie tych zmian w odpowiedniej kolejności.
Całą tę historię, w postaci plików z migracjami, należy trzymać w repozytorium wraz z kodem aplikacji. Chyba już teraz widać dlaczego - wszyscy członkowie zespołu mają tę samą historię bazy, a więc i strukturę bazy. Co więcej, na serwerze produkcyjnym również mamy tę samą strukturę bazy! Właściwie za darmo!
Wehikuł czasu — migracje wstecz i backupy bazy danychw Django
Migracje w Django nie tylko umożliwiają wprowadzanie zmian w bazie danych, ale również pozwalają na cofanie tych zmian. Dzięki migracjom wstecz (tzw. "rollback"), możemy wrócić do wcześniejszej wersji schematu bazy danych, co jest niezwykle przydatne w sytuacjach, gdy wprowadzone zmiany okazały się błędne lub niepotrzebne.
Na przykładzie modelu produktu w sklepie internetowym, który omawialiśmy wcześniej, pokaże, jak działają migracje wstecz.
Krok 1: Tworzenie początkowego modelu
Przypomnijmy sobie nasz początkowy model produktu:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField()
def __str__(self):
return self.namePo utworzeniu tego modelu, wykonaliśmy migracje, które utworzyły tabelę w bazie danych.
python manage.py makemigrations
python manage.py migrateKrok 2: Dodanie nowego pola
Dodaliśmy pole stock:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField()
stock = models.PositiveIntegerField(default=0) # nowe pole
def __str__(self):
return self.nameStworzyliśmy migrację i zastosowaliśmy ją:
python manage.py makemigrations
python manage.py migratePlik migracji 0002_add_stock_to_product.py można zobaczyć we wcześniejszej sekcji.
Krok 3: Migracje wstecz
Załóżmy, że chcemy cofnąć ostatnią zmianę, czyli usunąć pole stock. Możemy to zrobić za pomocą migracji wstecz. Aby cofnąć ostatnią migrację, używamy polecenia:
python manage.py migrate shop 0001Polecenie to cofa naszą bazę danych do stanu po pierwszej migracji (0001_initial), usuwając pole stock.
Sprawdzenie stanu migracji
Możemy sprawdzić obecny stan migracji w projekcie za pomocą polecenia:
python manage.py showmigrationsWynik w konsoli przed cofnięciem migracji:
shop
[X] 0001_initial
[X] 0002_add_stock_to_productWynik w konsoli po cofnięciu migracji:
shop
[X] 0001_initial
[ ] 0002_add_stock_to_productInformacje o migracjach w bazie danych
Django przechowuje informacje o wykonanych migracjach w specjalnej tabeli bazy danych o nazwie django_migrations. Tabela ta zawiera listę wszystkich wykonanych migracji, co pozwala na śledzenie, które migracje zostały zastosowane, a które nie. Dlatego brutalne usunięcie plików z migracjami nie zadziała, tylko spowoduje jeszcze więcej problemów.
Tabela django_migrations zawiera m.in. następujące kolumny:
- id: unikalny identyfikator migracji.
- app: nazwa aplikacji, do której należy migracja.
- name: nazwa migracji (np.
0001_initial). - applied: data i czas, kiedy migracja została zastosowana.
Przykładowe zapytanie SQL, aby zobaczyć zawartość tabeli django_migrations:
SELECT * FROM django_migrations;Wynik może wyglądać następująco:
id | app | name | applied
---|------|-------------------------|----------------------------
1 | shop | 0001_initial | 2024-07-13 12:00:00.000000
2 | shop | 0002_add_stock_to_product | 2024-07-13 12:05:00.000000Przykład cofania zmian
Gdy po dodaniu i usunięciu pola stock, zdecydowaliśmy się cofnąć wszystkie migracje do stanu początkowego, użyjemy polecenia:
python manage.py migrate shop zeroPolecenie zero cofa wszystkie migracje dla aplikacji shop, usuwając wszystkie tabele i zmiany wprowadzone przez migracje. Tak, usuwa dane. I tak, to jest polecenie, po którym możecie usunąć pliki z migracjami. Ale uwaga! Polecenie musi być wykonane na każdej bazie! Czyli u kolegów z zespołu też!
Przykład zastosowania migracji wstecz w praktyce
Wyobraźmy sobie, że wprowadziliśmy zmiany w naszym modelu, dodając pole category, a następnie chcemy cofnąć te zmiany.
Dodanie nowego pola:
# models.py from django.db import models class Product(models.Model): name = models.CharField(max_length=100) price = models.DecimalField(max_digits=10, decimal_places=2) description = models.TextField(null=True, blank=True) stock = models.PositiveIntegerField(default=0) category = models.CharField(max_length=50, default='general') # nowe pole def __str__(self): return self.nameTworzymy i stosujemy migrację:
python manage.py makemigrations python manage.py migratePlik migracji
0005_add_category_to_product.py:# 0005_add_category_to_product.py from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('shop', '0004_remove_stock_from_product'), ] operations = [ migrations.AddField( model_name='product', name='category', field=models.CharField(default='general', max_length=50), ), ]Cofanie migracji:
Teraz chcemy cofnąć tę migrację:
python manage.py migrate shop 0004To polecenie usunie pole
categoryz naszego modeluProduct, przywracając bazę danych do stanu po migracji0004_remove_stock_from_product. I teraz, jeśli stwierdzamy, że ta nowa migracja0005_add_category_to_product.pyjest błędna, to możemy usunąć ten plik, TYLKO I WYŁĄCZNIE WTEDY, gdy na wszystkich komputerach, na których była uruchomiona oryginalna migracja (0005_add_category_to_product.py), została ona wycofana. W praktyce, możemy robić co chcemy na naszej lokalnej bazie (na naszym komputerze). Jeśli migracja została dodana do repozytorium, to lepiej zrobić nową migrację cofającą zmiany - mniej boli. Serio, sprawdzałem.
.Awaria! Chcę wrócić!
Nic prostszego. Jeśli pliki nie zostały usunięte wystarczypython manage.py migrateEwentualne przywrócenie danych jest opisane w dalszej części posta.
Migracje wstecz w Django to potężne narzędzie, które pozwala programistom na cofanie zmian wprowadzonych do schematu bazy danych. Dzięki temu możemy testować i wprowadzać zmiany z większą pewnością, że w razie potrzeby będziemy mogli wrócić do wcześniejszej wersji schematu bazy danych. W naszym przykładzie modelu produktu w sklepie internetowym pokazaliśmy, jak łatwo jest dodać, zmodyfikować i usunąć pola oraz jak cofnąć te zmiany, korzystając z migracji wstecz. Dzięki migracjom wstecz, zarządzanie schematem bazy danych staje się bardziej elastyczne i bezpieczne.
Oczywiście trzeba uważać na usuwanie wartościowych danych. Wycofanie zmiany wprowadzającej category usunie dane z bazy (zawartość kolumny category), co może być trudne do przywrócenia. Pamiętajcie o regularnym tworzeniu kopii bezpieczeństwa bazy danych podczas eksperymentów.
Tu też nam pomaga Django, lub natywne silniki bazy.
Jak wykonać backup bazy danych w Django
Tworzenie backupów jest kluczowe dla zarządzania danymi w każdej aplikacji. W Django istnieje kilka metod, które umożliwiają tworzenie kopii zapasowych tabel lub całej aplikacji. Poniżej przedstawiam szczegółowe kroki, jak wykonać backup całej aplikacji shop.
Backup obejmuje wiele tabel i powiązanych danych. Możemy wykonać kopię zapasową bazy danych, która obejmie wszystkie tabele w aplikacji shop.
Krok 1: Eksportowanie danych
Możemy użyć narzędzia dumpdata, aby wyeksportować wszystkie dane z aplikacji shop do pliku JSON:
python manage.py dumpdata shop > shop_backup.jsonKrok 2: Importowanie danych
Aby zaimportować dane do nowej bazy danych lub odtworzyć kopię zapasową, możemy użyć narzędzia loaddata:
python manage.py loaddata shop_backup.jsonTe dwie komendy są wystarczające do eksperymentowania opisanego wcześniej. Przed wycofaniem migracji uruchamiacie dumpdata, cofamy migracje i sprawdzamy, czy wszystko jest w porządku. Jeśli nie, uruchamiamy
python manage.py migrate shopi potem loaddata. Wróciliśmy.
Alternatywne podejście: Backup bazy danych
Jeśli używamy bazy danych PostgreSQL, MySQL lub SQLite, możemy skorzystać z narzędzi specyficznych dla tych baz danych do tworzenia kopii zapasowych i przywracania danych.
PostgreSQL
# Backup
pg_dump mydatabase > mydatabase_backup.sql
# Restore
psql mydatabase < mydatabase_backup.sqlMySQL
# Backup
mysqldump -u username -p mydatabase > mydatabase_backup.sql
# Restore
mysql -u username -p mydatabase < mydatabase_backup.sqlSQLite
# Backup
sqlite3 mydatabase.db .dump > mydatabase_backup.sql
# Restore
sqlite3 mydatabase.db < mydatabase_backup.sqlW przypadku SQLite najłatwiejsze jest zwyczajne skopiowanie pliku z bazą danych - w końcu to baza oparta na plikach.
Tworzenie backupów bazy danych jest kluczowym procesem dla zachowania danych i bezpieczeństwa aplikacji. Kopię całej aplikacji można wykonać za pomocą narzędzi dumpdata i loaddata lub narzędzi specyficznych dla danej bazy danych. Dzięki tym narzędziom zarządzanie kopiami zapasowymi i przenoszenie danych staje się prostsze i bardziej efektywne, zapewniając integralność i dostępność danych w aplikacji.
Jak robić migracje danych w Django
Migracje w Django to nie tylko zmiany strukturalne bazy danych, takie jak dodawanie lub usuwanie kolumn. Django umożliwia także przeprowadzanie migracji danych, co pozwala na modyfikowanie istniejących danych w bazie. Migracje danych są niezwykle przydatne w sytuacjach, gdy zmiana struktury bazy wymaga dostosowania istniejących danych do nowego schematu.
Przykład migracji danych
Wyobraźmy sobie, że w naszym sklepie internetowym chcemy dodać nowe pole category do modelu Product i ustawić jego wartość dla istniejących produktów na podstawie ich opisu (description).
Krok 1: Dodanie nowego pola
Najpierw dodajmy nowe pole category do modelu Product:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField(null=True, blank=True)
stock = models.PositiveIntegerField(default=0)
category = models.CharField(max_length=50, default='general') # nowe pole
def __str__(self):
return self.nameTworzymy migrację dla tej zmiany:
python manage.py makemigrationsDjango wygeneruje plik migracji 0006_add_category_to_product.py:
# 0006_add_category_to_product.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shop', '0005_add_category_to_product'),
]
operations = [
migrations.AddField(
model_name='product',
name='category',
field=models.CharField(default='general', max_length=50),
),
]Krok 2: Migracja danych
Teraz chcemy ustawić wartość pola category na podstawie zawartości pola description. W tym celu musimy napisać migrację danych.
Utworzymy nowy plik migracji, który będzie zawierał operacje modyfikujące dane. Możemy to zrobić ręcznie lub skorzystać z polecenia makemigrations z flagą --empty:
python manage.py makemigrations shop --empty --name set_default_categoriesDjango wygeneruje pusty plik migracji 0007_set_default_categories.py, który możemy wypełnić naszymi operacjami:
# 0007_set_default_categories.py
from django.db import migrations
def set_default_categories(apps, schema_editor): # nasza funkcja
Product = apps.get_model('shop', 'Product')
for product in Product.objects.all():
if 'electronics' in product.description.lower():
product.category = 'electronics'
elif 'clothing' in product.description.lower():
product.category = 'clothing'
else:
product.category = 'general'
product.save()
class Migration(migrations.Migration):
dependencies = [
('shop', '0006_add_category_to_product'),
]
operations = [
migrations.RunPython(set_default_categories), # wywołanie naszej funkcji
]Krok 3: Zastosowanie migracji
Teraz, gdy mamy gotowe migracje strukturalne i danych, możemy je zastosować:
python manage.py migrateKiedy wykonamy to polecenie, Django zastosuje najpierw migrację 0006_add_category_to_product, dodając nowe pole category do tabeli Product, a następnie migrację 0007_set_default_categories, która zaktualizuje wartości pola category na podstawie zawartości pola description.
Szczegółowe wyjaśnienie kodu migracji danych
Importowanie modelu:
Product = apps.get_model('shop', 'Product')Używamy
apps.get_model, aby uzyskać modelProduct. Jest to konieczne, ponieważ bezpośrednie importowanie modeli będzie powodować problemy, gdyż migracje są stosowane w różnych momentach cyklu życia aplikacji. To taki wehikuł czasu - pobiera historyczny model właściwy dla danej migracji.Iteracja przez wszystkie produkty:
for product in Product.objects.all():Iterujemy przez wszystkie istniejące obiekty
Productw bazie danych. Uwaga! Jeśli został nadpisany manager obiektu, jak tutaj: https://github.com/pymasterspl/reddit/blob/a87ad9c5f8f611518b20b14fdb28008ea010c20b/core/models.py#L31-L32 to należy użyć managera wszystkich obiektów, w tym przypadkuall_objects. Kod pod linkiem to projekt, nad którym pracujemy wewnątrz społeczności PyMasters. Jeśli chcesz podnieść swoje umiejętności w Django i Pythonie, zapraszam do dołączenia do PyMasters i wzięcia udziału w projekcje!Ustawianie wartości pola
category:if 'electronics' in product.description.lower(): product.category = 'electronics' elif 'clothing' in product.description.lower(): product.category = 'clothing' else: product.category = 'general'Na podstawie zawartości pola
description, ustawiamy odpowiednią wartość polacategory.Zapisywanie zmian:
product.save()Zapisujemy zmiany dla każdego obiektu
Product.Definicja migracji:
class Migration(migrations.Migration): dependencies = [ ('shop', '0006_add_category_to_product'), ] operations = [ migrations.RunPython(set_default_categories), ]Migracja jest definiowana w standardowy sposób, z zależnością od poprzedniej migracji i operacją
RunPython, która uruchamia naszą funkcjęset_default_categories.
Migracje danych w Django pozwalają na wprowadzanie modyfikacji istniejących danych w bazie podczas migracji strukturalnych. Dzięki migracjom danych możemy automatycznie dostosowywać zawartość bazy danych do nowego schematu, co jest niezwykle przydatne w procesie rozwoju aplikacji. Przykład modelu produktu w sklepie internetowym pokazuje, jak łatwo można dodać nowe pole do modelu i zaktualizować jego wartość dla istniejących rekordów, korzystając z migracji danych.
W tej części to wszystko. Podsumowując, omówiliśmy:
- Czym są migracje w Django i jaka jest ich historia.
- Jak działają migracje na przykładzie modelu produktu w sklepie internetowym.
- Jak cofać migracje i zarządzać zmianami wstecz.
- Jak robić migracje danych z Django
W drugiej i ostatniej części skupimy się na:
- Migracje danych: Jak dodać pole z unikalną zawartością, gdy już mamy dane w bazie?
- Jak rozwiązać konflikty w migracjach?
- Jak, dzięki automatyzacji, nie zapomnieć dodać migracji do projektu
- Najpopularniejsze błędy migracji z Django i jak je rozwiązać
oraz spodziewajcie się BONUSA na koniec.
A jeśli szukasz miejsca, gdzie możesz wziąć udział w ciekawych projektach i podnosić swoje umiejętności w Pythonie i Django to dołącz do społeczności PyMasters
lub
potrzebujesz solidnej dawki wiedzy, to pobierz mój bezpłatny ebook: WARSZTAT JUNIORA Przewodnik po kluczowych kompetencjach i narzędziach dla początkującego programisty Pythona.
Zapraszam do zadawania pytań przez formularz kontaktowy. Pamiętaj, że jeśli potrzebujesz wsparcia, możesz napisać do mnie - pomogę.
Spodobał Ci się post?
Podziel się nim!
Masz uwagi do posta, chcesz porozmawiać, szukasz pomocy z Pythonem i Django? Napisz do mnie!