| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- from django.conf import settings
- class ChoiceSetMeta(type):
- """
- Metaclass for ChoiceSet
- """
- def __new__(mcs, name, bases, attrs):
- # Extend static choices with any configured choices
- if key := attrs.get('key'):
- assert type(attrs['CHOICES']) is list, f"{name} has a key defined but CHOICES is not a list"
- app = attrs['__module__'].split('.', 1)[0]
- replace_key = f'{app}.{key}'
- extend_key = f'{replace_key}+' if replace_key else None
- if replace_key and replace_key in settings.FIELD_CHOICES:
- # Replace the stock choices
- attrs['CHOICES'] = settings.FIELD_CHOICES[replace_key]
- elif extend_key and extend_key in settings.FIELD_CHOICES:
- # Extend the stock choices
- attrs['CHOICES'].extend(settings.FIELD_CHOICES[extend_key])
- # Define choice tuples and color maps
- attrs['_choices'] = []
- attrs['colors'] = {}
- for choice in attrs['CHOICES']:
- if isinstance(choice[1], (list, tuple)):
- grouped_choices = []
- for c in choice[1]:
- grouped_choices.append((c[0], c[1]))
- if len(c) == 3:
- attrs['colors'][c[0]] = c[2]
- attrs['_choices'].append((choice[0], grouped_choices))
- else:
- attrs['_choices'].append((choice[0], choice[1]))
- if len(choice) == 3:
- attrs['colors'][choice[0]] = choice[2]
- return super().__new__(mcs, name, bases, attrs)
- def __call__(cls, *args, **kwargs):
- # django-filters will check if a 'choices' value is callable, and if so assume that it returns an iterable
- return getattr(cls, '_choices', ())
- def __iter__(cls):
- return iter(getattr(cls, '_choices', ()))
- class ChoiceSet(metaclass=ChoiceSetMeta):
- """
- Holds an iterable of choice tuples suitable for passing to a Django model or form field. Choices can be defined
- statically within the class as CHOICES and/or gleaned from the FIELD_CHOICES configuration parameter.
- """
- CHOICES = list()
- @classmethod
- def values(cls):
- return [c[0] for c in unpack_grouped_choices(cls._choices)]
- def unpack_grouped_choices(choices):
- """
- Unpack a grouped choices hierarchy into a flat list of two-tuples. For example:
- choices = (
- ('Foo', (
- (1, 'A'),
- (2, 'B')
- )),
- ('Bar', (
- (3, 'C'),
- (4, 'D')
- ))
- )
- becomes:
- choices = (
- (1, 'A'),
- (2, 'B'),
- (3, 'C'),
- (4, 'D')
- )
- """
- unpacked_choices = []
- for key, value in choices:
- if isinstance(value, (list, tuple)):
- # Entered an optgroup
- for optgroup_key, optgroup_value in value:
- unpacked_choices.append((optgroup_key, optgroup_value))
- else:
- unpacked_choices.append((key, value))
- return unpacked_choices
- #
- # Generic color choices
- #
- class ColorChoices(ChoiceSet):
- COLOR_DARK_RED = 'aa1409'
- COLOR_RED = 'f44336'
- COLOR_PINK = 'e91e63'
- COLOR_ROSE = 'ffe4e1'
- COLOR_FUCHSIA = 'ff66ff'
- COLOR_PURPLE = '9c27b0'
- COLOR_DARK_PURPLE = '673ab7'
- COLOR_INDIGO = '3f51b5'
- COLOR_BLUE = '2196f3'
- COLOR_LIGHT_BLUE = '03a9f4'
- COLOR_CYAN = '00bcd4'
- COLOR_TEAL = '009688'
- COLOR_AQUA = '00ffff'
- COLOR_DARK_GREEN = '2f6a31'
- COLOR_GREEN = '4caf50'
- COLOR_LIGHT_GREEN = '8bc34a'
- COLOR_LIME = 'cddc39'
- COLOR_YELLOW = 'ffeb3b'
- COLOR_AMBER = 'ffc107'
- COLOR_ORANGE = 'ff9800'
- COLOR_DARK_ORANGE = 'ff5722'
- COLOR_BROWN = '795548'
- COLOR_LIGHT_GREY = 'c0c0c0'
- COLOR_GREY = '9e9e9e'
- COLOR_DARK_GREY = '607d8b'
- COLOR_BLACK = '111111'
- COLOR_WHITE = 'ffffff'
- CHOICES = (
- (COLOR_DARK_RED, 'Dark Red'),
- (COLOR_RED, 'Red'),
- (COLOR_PINK, 'Pink'),
- (COLOR_ROSE, 'Rose'),
- (COLOR_FUCHSIA, 'Fuchsia'),
- (COLOR_PURPLE, 'Purple'),
- (COLOR_DARK_PURPLE, 'Dark Purple'),
- (COLOR_INDIGO, 'Indigo'),
- (COLOR_BLUE, 'Blue'),
- (COLOR_LIGHT_BLUE, 'Light Blue'),
- (COLOR_CYAN, 'Cyan'),
- (COLOR_TEAL, 'Teal'),
- (COLOR_AQUA, 'Aqua'),
- (COLOR_DARK_GREEN, 'Dark Green'),
- (COLOR_GREEN, 'Green'),
- (COLOR_LIGHT_GREEN, 'Light Green'),
- (COLOR_LIME, 'Lime'),
- (COLOR_YELLOW, 'Yellow'),
- (COLOR_AMBER, 'Amber'),
- (COLOR_ORANGE, 'Orange'),
- (COLOR_DARK_ORANGE, 'Dark Orange'),
- (COLOR_BROWN, 'Brown'),
- (COLOR_LIGHT_GREY, 'Light Grey'),
- (COLOR_GREY, 'Grey'),
- (COLOR_DARK_GREY, 'Dark Grey'),
- (COLOR_BLACK, 'Black'),
- (COLOR_WHITE, 'White'),
- )
- #
- # Button color choices
- #
- class ButtonColorChoices(ChoiceSet):
- """
- Map standard button color choices to Bootstrap 3 button classes
- """
- DEFAULT = 'outline-dark'
- BLUE = 'blue'
- INDIGO = 'indigo'
- PURPLE = 'purple'
- PINK = 'pink'
- RED = 'red'
- ORANGE = 'orange'
- YELLOW = 'yellow'
- GREEN = 'green'
- TEAL = 'teal'
- CYAN = 'cyan'
- GRAY = 'gray'
- GREY = 'gray' # Backward compatability for <3.2
- BLACK = 'black'
- WHITE = 'white'
- CHOICES = (
- (DEFAULT, 'Default'),
- (BLUE, 'Blue'),
- (INDIGO, 'Indigo'),
- (PURPLE, 'Purple'),
- (PINK, 'Pink'),
- (RED, 'Red'),
- (ORANGE, 'Orange'),
- (YELLOW, 'Yellow'),
- (GREEN, 'Green'),
- (TEAL, 'Teal'),
- (CYAN, 'Cyan'),
- (GRAY, 'Gray'),
- (BLACK, 'Black'),
- (WHITE, 'White'),
- )
|