# Imports
from string import ascii_letters as letters
from django.core.exceptions import FieldError
from django.db import models
from django.utils.crypto import get_random_string
from django.utils.translation import ugettext_lazy as _
# Exports
__all__ = (
"RandomCharField",
)
# Fields
[docs]class RandomCharField(models.CharField):
"""Generates random characters when the field is saved.
**Possible Uses**
- Create a confirmation token for password resets or account creation.
- Assist with SPAM prevention.
"""
description = _("Generates random characters when the field is saved.")
[docs] def __init__(self, *args, **kwargs):
# Set defaults.
kwargs.setdefault('blank', True)
kwargs.setdefault('max_length', 62)
# Initialize and letter errors bubble up before we continue.
super().__init__(*args, **kwargs)
# Validate max_length.
length = kwargs['max_length']
if length > 62:
message = "max_length cannot be greater than 62 for RandomCharField."
raise FieldError(message)
# Set the list of available characters based on max_length.
characters = letters + '0123456789'
self.characters = characters[:length]
[docs] def generate_text(self):
"""Generate the random text."""
return get_random_string(self.max_length, self.characters)
[docs] def pre_save(self, model_instance, add):
"""Set the value of the field to a random string of text."""
# if not add and getattr(model_instance, self.attname) != '':
# return getattr(model_instance, self.attname)
#
# value = self.generate_text()
# setattr(model_instance, self.attname, value)
#
# return value
# There is no need to generate a random string twice.
value = getattr(model_instance, self.attname)
# print("existing value", model_instance, self.attname, value)
if not value:
value = self.generate_text()
setattr(model_instance, self.attname, value)
return value