1

So I'm using python secrets library so I can generate token, so I want to add it as a default like this

token=models.CharField(max_length=32, default=secrets.token_urlsafe(32))

strange thing it will generate 43 characters rather than 32, so can anyone help me understand why?

Thanks

copser
  • 2,523
  • 5
  • 38
  • 73

1 Answers1

4

That default argument must point to a callable, not a function call with arguments (which are only evaluated once when Django starts). You need to write your own wrapper function and refer to that instead. For example:

def my_secret():
    return secrets.token_urlsafe(32)[:32] # Return only the first 32 characters.
#...
token=models.CharField(max_length=32, default=my_secret)

Refer to this answer: https://stackoverflow.com/a/12654998/4082726


Regarding the length: token_urlsafe's argument is the number of bytes, not characters. According to the documentation this means roughly 1.3 characters per byte, so 32 * 1.3 = ~42.

malberts
  • 2,488
  • 1
  • 11
  • 16
  • yes, but it will return the same, I'm experimenting right now, basically it somehow generating more then it should be – copser Feb 13 '19 at 17:44
  • Oh, I see. According to the documentation it generates ~1.3 characters per byte. That argument is not the number of characters, but rather bytes. So 32 * 1.3 = ~42. See here: https://docs.python.org/3/library/secrets.html#secrets.token_urlsafe – malberts Feb 13 '19 at 17:45
  • What `save()` method? If you really want only 32 to characters, then you can just slice the string. I will update the answer. – malberts Feb 13 '19 at 17:47
  • 1
    Note to @malberts: the arguments are not ignored actually (that part of your answer is wrong). The problem with calling the function is that it's only called once when Django is started and loaded in memory, so every user would receive the same token until you restart your app server. By setting `default` to a *callable* you ensure it's run every time a new instance is initialised. – dirkgroten Feb 13 '19 at 17:50