Search code examples
pythondjangorandompasswordssecrets

Why does the Python Secrets module keep generating the same passwords in this function in Django


Here is the function:

def generate_password():
    alphabet = string.ascii_letters + string.digits + "!@#$%^&*()+=/.,"
    return ''.join(secrets.choice(alphabet) for i in range(12))

I added this to a Django model, so that it is automatically called when creating a user, and automatically generates its password. This is the code in the model:

password = models.CharField(max_length=100, default=generate_password())

For some reason, creating 4 users is always going to create at least one duplicate password, if not two.

this is an example of the passwords generated by creating 7 users:

PpN(ky^tabgP
iIS@4gfe@7sc
6#oNlIH0MbQg
6#oNlIH0MbQg
iIS@4gfe@7sc
PpN(ky^tabgP
PpN(ky^tabgP

This approach was suggested by different people and documentation, yet it seems like this function is always cycling between only a few passwords, and keeps repeating them.

Can anyone help me understand why and how to avoid it?

Django needs to be restarted some times so adding passwords to a set is not convenient.


Solution

  • The problem is here.

    password = models.CharField(max_length=100, default=generate_password())
    

    It must be(without parentheses)

    password = models.CharField(max_length=100, default=generate_password)
    

    because you need to pass a callable object as default argument and it will be called by django when every time a new object is created.

    But that's not the case with your current code. Since you are using parentheses (), the function generate_password immediately gets invoked and return value gets assigned to the default.