Coverage for utilities/forms/fields/array.py: 42%

33 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 18:35 +0000

1from django import forms 

2from django.contrib.postgres.forms import SimpleArrayField 

3from django.utils.safestring import mark_safe 

4from django.utils.translation import gettext_lazy as _ 

5 

6from utilities.data import ranges_to_string, string_to_ranges 

7 

8from ..utils import parse_numeric_range 

9 

10__all__ = ( 

11 'NumericArrayField', 

12 'NumericRangeArrayField', 

13) 

14 

15 

16class NumericArrayField(SimpleArrayField): 

17 

18 def clean(self, value): 

19 if value and not self.to_python(value): 

20 raise forms.ValidationError( 

21 _("Invalid list ({value}). Must be numeric and ranges must be in ascending order.").format(value=value) 

22 ) 

23 return super().clean(value) 

24 

25 def to_python(self, value): 

26 if not value: 

27 return [] 

28 if isinstance(value, str): 

29 value = ','.join([str(n) for n in parse_numeric_range(value)]) 

30 return super().to_python(value) 

31 

32 

33class NumericRangeArrayField(forms.CharField): 

34 """ 

35 A field which allows for array of numeric ranges: 

36 Example: 1-5,10,20-30 

37 """ 

38 def __init__(self, *args, help_text='', **kwargs): 

39 if not help_text: 39 ↛ 45line 39 didn't jump to line 45 because the condition on line 39 was always true

40 help_text = mark_safe( 

41 _( 

42 "Specify one or more individual numbers or numeric ranges separated by commas. Example: {example}" 

43 ).format(example="<code>1-5,10,20-30</code>") 

44 ) 

45 super().__init__(*args, help_text=help_text, **kwargs) 

46 

47 def clean(self, value): 

48 if value and not self.to_python(value): 

49 raise forms.ValidationError( 

50 _("Invalid ranges ({value}). Must be a range of integers in ascending order.").format(value=value) 

51 ) 

52 return super().clean(value) 

53 

54 def prepare_value(self, value): 

55 if isinstance(value, str): 

56 return value 

57 return ranges_to_string(value) 

58 

59 def to_python(self, value): 

60 return string_to_ranges(value)