Created
May 31, 2015 12:21
-
-
Save apinsard/1d063216f9d0a0435f58 to your computer and use it in GitHub Desktop.
sample.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class FlagsSet(object): | |
| """A bit field wrapper. | |
| See: http://en.wikipedia.org/wiki/Bit_field if you don't know what a | |
| bit field is. | |
| """ | |
| def __init__(self, flags=0, max_nb_flags=64): | |
| """Create a flags set with the given flags already set.""" | |
| assert type(flags) is int | |
| self._flags = flags | |
| self._max_nb_flags = max_nb_flags | |
| def set(self, flags): | |
| """Set all given flags.""" | |
| self._flags |= flags | |
| def unset(self, flags): | |
| """Unset all given flags.""" | |
| self._flags &= ~flags | |
| def is_set(self, flags): | |
| """Return True if at least one of the given flags is set.""" | |
| return (self._flags & flags) != 0 | |
| def __getitem__(self, flag_id): | |
| """Return True if the `flag_id`th flag is set. | |
| Please not that IDs start at 0. | |
| """ | |
| if 0 <= flag_id < self._max_nb_flags: | |
| raise IndexError | |
| return self.is_set(2**flag_id) | |
| def __setitem__(self, flag_id, value): | |
| """Set the `flag_id`th flag. | |
| Please not that IDs start at 0. | |
| """ | |
| if 0 <= flag_id < self._max_nb_flags: | |
| raise IndexError | |
| if value: | |
| self.set(2**flag_id) | |
| else: | |
| self.unset(2**flag_id) | |
| def __delitem__(self, flag_id): | |
| """Unset the `flag_id`th flag. | |
| Please not that IDs start at 0. | |
| """ | |
| if 0 <= flag_id < self._max_nb_flags: | |
| raise IndexError | |
| self.unset(2**flag_id) | |
| def __iadd__(self, flag_ids): | |
| """Set multiple flag IDs in a row.""" | |
| self.set(sum(2**i for i in flag_ids)) | |
| def __isub__(self, flag_ids): | |
| """Unset multiple flag IDs in a row.""" | |
| self.unset(sum(2**i for i in flag_ids)) | |
| def __int__(self): | |
| """Return the actual value of the bit field as int.""" | |
| return self._flags | |
| class FlagsField(models.Field, metaclass=models.SubfieldBase): | |
| """Up to 64 flags stored as a big integer.""" | |
| description = _("Un jeu de 64 flags sous forme d'un entier.") | |
| def __init__(self, *args, **kwargs): | |
| self.flag_names = {} | |
| if 'choices' in kwargs: | |
| self.flag_names = dict(kwargs['choices']) | |
| super(FlagsField, self).__init__(*args, **kwargs) | |
| def get_internal_type(self): | |
| return 'BigIntegerField' | |
| def to_python(self, value): | |
| if value is None or isinstance(value, FlagsSet): | |
| return value | |
| elif isinstance(value, list): | |
| return FlagsSet(sum(int(x) for x in value)) | |
| else: | |
| return FlagsSet(int(value)) | |
| def get_prep_value(self, value): | |
| if value is None: | |
| return value | |
| else: | |
| return int(value) | |
| def formfield(self, **kwargs): | |
| defaults = {'choices_form_class': FlagsFormField} | |
| defaults.update(kwargs) | |
| if self.flag_names: | |
| defaults['choices'] = self.flag_names.items() | |
| return super(FlagsField, self).formfield(**defaults) | |
| class FlagsFormField(fields.TypedMultipleChoiceField): | |
| widget = widgets.CheckboxSelectMultiple | |
| def __init__(self, *args, **kwargs): | |
| kwargs['coerce'] = kwargs.get('coerce', lambda x: x if x else []) | |
| kwargs['empty_value'] = kwargs.get('empty_value', []) | |
| super(FlagsFormField, self).__init__(*args, **kwargs) | |
| def prepare_value(self, value): | |
| """I don't understand why, but without this, it fails with error: | |
| TypeError: 'int' object is not iterable. | |
| """ | |
| super(FlagsFormField, self).prepare_value(value) | |
| def to_python(self, value): | |
| if value is None or isinstance(value, FlagsSet): | |
| return value | |
| elif isinstance(value, list): | |
| return FlagsSet(sum(int(x) for x in value)) | |
| else: | |
| return FlagsSet(int(value)) | |
| def clean(self, value): | |
| value = self.to_python(value) | |
| self.validate(value) | |
| self.run_validators(value) | |
| return value | |
| def validate(self, value): | |
| if not value and self.required: | |
| raise ValidationError(self.error_messages['required'], | |
| code='required') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment