Distributing Django projects with unique SECRET_KEYs

前端 未结 10 949
长发绾君心
长发绾君心 2020-12-22 16:41

I have a Django project that I\'d like to distribute on a public repository like bitbucket or github. I\'d like it to be as easy to install as possible, so I\'m including t

相关标签:
10条回答
  • 2020-12-22 16:58

    I'd go about it this way:

    Have the secret key in a separate file "secret_key.py". This file does not exist for a pristine installation. In your settings.py include something like:

    try:
        from .secret_key import SECRET_KEY
    except ImportError:
        SETTINGS_DIR = os.path.abspath(os.path.dirname(__file__))
        generate_secret_key(os.path.join(SETTINGS_DIR, 'secret_key.py'))
        from .secret_key import SECRET_KEY
    

    The function generate_secret_key(filename) that you will write generates a file called filename (which, as we call it, will be secret_key.py in the same dir as settings.py) with the contents:

    SECRET_KEY = '....random string....'
    

    Where random string is the generated key based on a random number.

    For key generation you can use Umang's suggestion https://stackoverflow.com/a/16630719/166761.

    0 讨论(0)
  • 2020-12-22 16:59

    I would solve the problem like this:

    • Provide a dummy secret key like: I_AM_A_DUMMY_KEY_CHANGE_ME
    • Create a manage command to generate a new one: ./manage.py gen_secret_key
    • In the documentation, STRONGLY advise users to run the command as soon as possible
    0 讨论(0)
  • 2020-12-22 17:03

    Generally speaking, you can divide Django configuration into things that are app-specific and things that are server-specific. This falls into the latter category.

    There are a number of ways you can tackle the problem of server-specific configuration, it is discussed more in this question.

    For this particular instance, using the approach I outline in my answer to the other question, I'd put a placeholder in settings_local.py.sample for distribution, and during installation, I'd copy that over to settings_local.py and edit to suit.

    0 讨论(0)
  • 2020-12-22 17:10

    In this solution I use django-dotenv, which is one of the dependencies of my project, as listed in requirements.txt like django-dotenv==1.4.1. The advantage of this approach is you have a different .env file for each environment where the application is installed.

    Create the file utils.py in the same directory of settings.py with the following content:

    from django.utils.crypto import get_random_string
    
    def generate_secret_key(env_file_name):
        env_file = open(env_file_name, "w+")
        chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
        generated_secret_key = get_random_string(50, chars)
        env_file.write("SECRET_KEY = '{}'\n".format(generated_secret_key))
        env_file.close()
    

    Then modify the settings.py file as follows:

    import dotenv
    from [project-folder-name] import utils
    ...
    try:
        SECRET_KEY = os.environ['SECRET_KEY']
    except KeyError:
        path_env = os.path.join(BASE_DIR, '.env')
        utils.generate_secret_key(path_env)
        dotenv.read_dotenv(path_env)
        SECRET_KEY = os.environ['SECRET_KEY']
    

    For those who don't use django-dotenv, all you have to do it to add it as a dependency and change the manage.py to load it at startup:

    import dotenv
    
    if __name__ == "__main__":
        dotenv.read_dotenv()
    
    0 讨论(0)
  • 2020-12-22 17:12

    Carles Barrobés made an excellent answer but it is incomplete, here is my version for python 3 with the missing function to work.

    from django.core.management.utils import get_random_secret_key
    
    def generate_secret_key (filepath):
        secret_file = open(filepath, "w")
        secret = "SECRET_KEY= " + "\""+ get_random_secret_key() + "\"" + "\n"
        secret_file.write(secret)
        secret_file.close()
    
    try:
        from .secret_key import SECRET_KEY
    except ModuleNotFoundError:
    
        SETTINGS_DIR = os.path.abspath(os.path.dirname(__file__))
        generate_secret_key(os.path.join(SETTINGS_DIR, 'secret_key.py'))
        from .secret_key import SECRET_KEY
    

    Take notice that I changed the ImportError for ModuleNotFoundError and creates the python file secret_key.py to gather the SECRET_KEY like a variable instead to parse a txt file.

    0 讨论(0)
  • 2020-12-22 17:13

    In my code I have three levels of settings file inspired by Two Scoops of Django, so a middle one goes like this where BASE_PRIVATE_DIR is set up in the base template. In my case this is from the django directory ../../mysite_private but somewhere ouside the normal files under the application git.:

    from .base import *
    
    ALLOWED_HOSTS = ['staging.django.site'] 
    #Allow local override which is per deployment instance.  There should probably then be
    #  an instance git for version control of the production data
    try:
        import sys
        private_path = BASE_PRIVATE_DIR.child('production')
        sys.path.append(private_path)
        from private_settings import *
    except ImportError:
        print(" No production overide private_settings.py found.  This is probably an error  = {}".format(private_path))
        # If it doesnt' exist that is fine and just use system and environment defaults
    
    0 讨论(0)
提交回复
热议问题