[Django]-Is there a function for generating settings.SECRET_KEY in django?

54👍

Indeed, you can use the same function that generates a new key when you call startproject, which is django.core.management.utils.get_random_secret_key().

Note however it’s not very different from your version.

107👍

Note that this may not be safe to use for production, as S Ghosh is pointing out in a post below. But copy and paste this after running django-admin shell for example to quickly get a key.

from django.core.management.utils import get_random_secret_key  
get_random_secret_key()

44👍

Run this command below on the Terminal.

$ python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'

output:

2x$e%!k_u_0*gq0s4!_u(2(^lpy&gir0hg)q&5nurj0-sseuav

20👍

I would like to add that as per the commit Fixed #31757 — Adjusted system check for SECRET_KEY to warn about autogenerated default keys, the method get_random_secret_key() is considred to be insecure.

If you are using python 3.6+ then you can use the secrets.token_hex([nbytes=None]) function

python3 -c 'import secrets; print(secrets.token_hex(100))'

credit TLDR: Generate Django Secret Key

10👍

The post referenced by S Ghosh TLDR: Generate Django Secret Key indicates that as of version 3.1.3, Django is actually using the Python secrets module behind the scenes. Looking at this blob for get_random_secret_key and this other blob for get_random_string, I can see it is so:

def get_random_secret_key():
    """
    Return a 50 character random string usable as a SECRET_KEY setting value.
    """
    chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
    return get_random_string(50, chars)
def get_random_string(length, allowed_chars=RANDOM_STRING_CHARS):
    """
    Return a securely generated random string.
    The bit length of the returned value can be calculated with the formula:
        log_2(len(allowed_chars)^length)
    For example, with default `allowed_chars` (26+26+10), this gives:
      * length: 12, bit length =~ 71 bits
      * length: 22, bit length =~ 131 bits
    """
    return ''.join(secrets.choice(allowed_chars) for i in range(length))

The only issue with the get_random_secret_key function as I see it in the code is that the allowed characters does not include capital letters, so the number of possible bits for the same size key is smaller than it would be if capitals were included, but not by much:

from math import log2
lower_plus_numbers = (list(chr(o) for o in range(0x61, 0x7B))
                      + list(chr(o) for o in range(0x30, 0x3A)))
punctuation = list('!@#$%^&*(-_=+)')
upper_alpha = list(chr(o) for o in range(0x41, 0x5B))
shorter = log2((len(lower_plus_numbers) + len(punctuation)) ** 50)
longer = log2((len(lower_plus_numbers) + len(punctuation) + len(upper_alpha)) ** 50)
print(f'longer: {int(longer + 0.5)}; shorter: {int(shorter + 0.5)} '
      f'difference: {int(longer - shorter + 0.5)}; ratio: {longer/shorter}')

The output of the above code:

longer: 312; shorter: 282; difference: 30; ratio: 1.1070316647619918

So, if you have a recent enough Django and Python, the biggest question is whether you want to generate your SECRET_KEY with a dependency on Dango, or just Python. If you don’t mind the Django dependency, but want to include upper case letters, or want to have a longer key, you can easily do something like:

from django.utils.crypto import get_random_string
key_length = 60
get_random_string(
    key_length,
    allowed_chars=lower_plus_numbers + punctuation + upper_alpha,
)

Sample output:

'gW(VDtylhoAuZNcLbIC=ai5=2*tPZ=Gmf4D1^4T!NxX3tB0%_w7pYY2+FgDx'

If you don’t want the Django dependency, you could use S Ghosh’s answer. Or if you want more than hex characters, you could do something like:

allowed_chars = [chr(i) for i in range(0x21, 0x7F)]
key_length = 60
key = ''.join(secrets.choice(allowed_chars) for i in range(key_length))

Value of key (as a python string):

'DN7tbWid#q6R^=%i"[1AA>$@AZg=XD+p|[aB?:#V`:kKWL77P6dC,~(\\9O\'j'

Leave a comment