DB and migration reset

At the moment when migrations don’t work I have to do a lot of things to get projects working again; and I always make mistakes and have to do it all multiple times :frowning:

The actions:

  • I delete all migrations folders,
  • remove the database,
  • use: python manage.py migrate to create the database again
  • I have to use python manage.py makemigrations app-name for every app I created separately in a specific order
  • and then I can use python manage.py migrate
  • Next I use python manage.py populate_db many thanks to Automate populating database
    and I think I forgot some things

So I am not happy and want to automate this but cant find out how so…

  • How van I create a command (python manage.py resetapps or something like that) to perform all commands shown above?
  • Can I place the populate_db code etc in the ‘root’ / MySite folder somewhere? That feels like the correct place for the code because it populates the database for all apps. And if not… why?

And for my understanding:

  • Why do I need to use python manage.py makemigrations app-name for every app instead of once for all apps?

See django-admin and manage.py | Django documentation | Django

and

See How to create custom django-admin commands | Django documentation | Django

Also, see How to provide initial data for models | Django documentation | Django

Thanks I will check it out and post my result here.

I will post the code here. It does not work with fixtures for me but might work for others and it seems to be a better solution for testing so here it is. I have some print calls to show me the progress.

  1. As described in management command docs I created the reset_data.py file in the App1/management/commands folder.
  2. Deleted all the files (db and migrations)
  3. Migrated all again
  4. filled the database again. (fixtures seems the best way but fails for me so I show two solutions).

The code:

from django.contrib.auth.models import User
from App1.models import *
from App2.models import * #etc

For folder and file manipulation
import os
from os.path import exists
from pathlib import Path
import shutil

For the commands
from django.core import management
from django.core.management.commands import migrate
from django.core.management.base import BaseCommand

class Command(BaseCommand):
args = ‘<foo bar …>’
help = ‘our help string comes here’

def handle(self, *args, **options):
    self._reset_migrations()
    self._migrate_apps()

    #This works but is not supported for testing so ignore this code if you can
    self._create_user()
    self._create_data()

    #For me this fails but it seems nice.
    self._populate_db_from_fixtures()

def _reset_migrations(self):
    cwd = os.getcwd()
    # This is the code for sqlite db file deletion. Change for other databases.
    db_file = cwd + '\db.sqlite3'
    if(Path(db_file).is_file() ):
        os.remove(db_file)

    i = 0
    for subdir, dirs, files in os.walk(cwd):
        if(os.path.basename(os.path.normpath(subdir)) == "migrations"):
            i = i+1
            shutil.rmtree(subdir)
    print('%i migration folders found and deleted' %(i)) 

def _migrate_apps(self):
    print('\nmigrate all apps.')
    print('Initial migration for the basics')
    management.call_command('migrate')

For dependencies you might need to migrate apps separately.
print(‘\nmigrate Account’)
management.call_command(‘makemigrations’, ‘Account’)
management.call_command(‘migrate’)

    # Or in bulk...call makemigrations for each app because the migrations directory does not excist
    print('\nmigrate all other apps')
    management.call_command('makemigrations', 'App1')
    management.call_command('makemigrations', 'App2')

management.call_command(‘migrate’)

#THE TWO SOLUTIONS for filling the database
#OPTION 1: This is a beauty if it works (How to provide initial data for models | Django documentation | Django)
def _populate_db_from_fixtures(self):
# Load the data from fixture files
management.call_command(‘loaddata’, ‘data.json’)

#OPTION 2: This is the working solution for myself.
def _create_user(self):
print(‘Create user’)
u = User.objects.create_superuser(username=‘admin’, email=None, password=None)
u.set_password(‘Myfantasticpassword1234#%$IalwaysFORGET’)
u.save()

def _create_data(self):
print(‘Fill database’)

    A1 = App1(title='A perfect title')
    A1.save()

    S1 = App2(name='The name', parent=A1)
    S1.save()

I missed this sentence 100 times but …As described in the documentation “To add migrations to an app that doesn’t have a migrations directory, run makemigrations with the app’s app_label” So after deleting the all migration folders I have to call makemigrations per app. Reading is hard :wink:

With fixtures I have a few problems and things that feel over-complicated (passwords etc); or I just dont understand them :slight_smile:

I started with a database filled with data. I used the command for dumpdata to create the fixture file (in the root app): python manage.py dumpdata > data.json; sorry forgot where to place the file afterwards) When using this file I got a UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xff in position 0: invalid start byte; Beside some more problems I decided to use my current trusted solution for filling the database.

I hope this is usefull for someone.

(edit to make it look a bit better)