1from django.core.validators import RegexValidator 2from django.db import models 3 4from utilities.ordering import naturalize 5from .forms import ColorSelect 6 7ColorValidator = RegexValidator( 8 regex='^[0-9a-f]{6}$', 9 message='Enter a valid hexadecimal RGB color code.', 10 code='invalid' 11) 12 13 14# Deprecated: Retained only to ensure successful migration from early releases 15# Use models.CharField(null=True) instead 16class NullableCharField(models.CharField): 17 description = "Stores empty values as NULL rather than ''" 18 19 def to_python(self, value): 20 if isinstance(value, models.CharField): 21 return value 22 return value or '' 23 24 def get_prep_value(self, value): 25 return value or None 26 27 28class ColorField(models.CharField): 29 default_validators = [ColorValidator] 30 description = "A hexadecimal RGB color code" 31 32 def __init__(self, *args, **kwargs): 33 kwargs['max_length'] = 6 34 super().__init__(*args, **kwargs) 35 36 def formfield(self, **kwargs): 37 kwargs['widget'] = ColorSelect 38 return super().formfield(**kwargs) 39 40 41class NaturalOrderingField(models.CharField): 42 """ 43 A field which stores a naturalized representation of its target field, to be used for ordering its parent model. 44 45 :param target_field: Name of the field of the parent model to be naturalized 46 :param naturalize_function: The function used to generate a naturalized value (optional) 47 """ 48 description = "Stores a representation of its target field suitable for natural ordering" 49 50 def __init__(self, target_field, naturalize_function=naturalize, *args, **kwargs): 51 self.target_field = target_field 52 self.naturalize_function = naturalize_function 53 super().__init__(*args, **kwargs) 54 55 def pre_save(self, model_instance, add): 56 """ 57 Generate a naturalized value from the target field 58 """ 59 original_value = getattr(model_instance, self.target_field) 60 naturalized_value = self.naturalize_function(original_value, max_length=self.max_length) 61 setattr(model_instance, self.attname, naturalized_value) 62 63 return naturalized_value 64 65 def deconstruct(self): 66 kwargs = super().deconstruct()[3] # Pass kwargs from CharField 67 kwargs['naturalize_function'] = self.naturalize_function 68 return ( 69 self.name, 70 'utilities.fields.NaturalOrderingField', 71 [self.target_field], 72 kwargs, 73 ) 74