Forums

Django: best practice for database mangement in dev and prod

Right now I use an "if-else" clause to switch between my development database and my production, depending on an environment variable:

if os.environ["DJANGO_DEBUG"] == True:
    DATABASES = {
        "default": {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': os.environ["DB_NAME"],
            'USER': os.environ["DB_USER"],
            'PASSWORD': os.environ["DB_PW"],
            'HOST': os.environ["DB_HOST"],
    }
}

Since I am fairly new to Django, my question is, if this is a legit and advisable approach or are there better/alternative ways to archive the same?

I can't see any serious problems with that solution, no, and if you're happy with it then you can safely go ahead doing things that way.

But things might get more complicated if you want to have other things that differ between the different environments. For example, in PythonAnywhere itself -- our front-end is a Django application -- the live site has not only different database settings, but different PayPal API keys, Stripe keys, email addresses, and so on. And if you use a big "if" statement to contain the different bits, it could become unmanageable.

Django developers have heated debates about what the "best" way to handle that kind of thing is. A popular solution, however, is to have multiple settings files. Instead of having a settings.py file, you'd have a directory called settings in the same location. In that directory, you'd have a file called __init__.py that looked like this:

from .common_settings import *
from .local_settings import *

You would also have files there called dev_settings.py and prod_settings.py, which would contain the specific settings for those environments, and common_settings.py to hold (of course) the stuff that was common to all environments.

The final step is the local_settings.py file, also in the settings directory. If you're using git, this one would be in your .gitignore file and would be something you'd create when you check out the repository. (If you're not using git, it's just a file.)

It would just import stuff from whichever environment file you wanted to use for that code tree -- for example, for production, it would be:

from .prod_settings import *

Hope that helps!

So, it is true what they say in the interwebs: the PythonAnywhere staff is quick to respond and in a kind and helpful way ;-) Much appreciated.

I see what you mean with "could become unmanageable". And indeed I already have a base.py, a dev.py and a production.py. But somehow I did not manage to separate the database configs. But – I just tried again, and now it works. So I got rid of the if-else switch.

May I ask for some clarification on the local_settings.py? I do not understand its use. In your example you say it could contain:

import from .prod_settings *

But I all already have a production.py, right? Or is the intended use case for importing variables like SECRET_KEY and such?

yes, I think Giles means that you can have all the configs that should not be in version control in a separate settings file that is gitignore-d, and while you import that settings file and use it in your code, it will be different for different deployments and not kept in record anywhere.