class MySQLNullBooleanForm(Form): nullbool0 = NullBooleanField(widget=RadioSelect( choices=NULLBOOL_CHOICES)) nullbool1 = NullBooleanField(widget=RadioSelect( choices=NULLBOOL_CHOICES)) nullbool2 = NullBooleanField(widget=RadioSelect( choices=NULLBOOL_CHOICES))
def test_nullbooleanfield_changed(self): f = NullBooleanField() self.assertTrue(f.has_changed(False, None)) self.assertTrue(f.has_changed(None, False)) self.assertFalse(f.has_changed(None, None)) self.assertFalse(f.has_changed(False, False)) self.assertTrue(f.has_changed(True, False)) self.assertTrue(f.has_changed(True, None)) self.assertTrue(f.has_changed(True, False))
class ThreadListGetForm(_PaginationForm): """ A form to validate query parameters in the thread list retrieval endpoint """ EXCLUSIVE_PARAMS = ["topic_id", "text_search", "following"] course_id = CharField() topic_id = MultiValueField(required=False) text_search = CharField(required=False) following = NullBooleanField(required=False) view = ChoiceField( choices=[(choice, choice) for choice in ["unread", "unanswered"]], required=False, ) order_by = ChoiceField( choices=[(choice, choice) for choice in ["last_activity_at", "comment_count", "vote_count"]], required=False ) order_direction = ChoiceField( choices=[(choice, choice) for choice in ["asc", "desc"]], required=False ) def clean_order_by(self): """Return a default choice""" return self.cleaned_data.get("order_by") or "last_activity_at" def clean_order_direction(self): """Return a default choice""" return self.cleaned_data.get("order_direction") or "desc" def clean_course_id(self): """Validate course_id""" value = self.cleaned_data["course_id"] try: return CourseLocator.from_string(value) except InvalidKeyError: raise ValidationError("'{}' is not a valid course id".format(value)) def clean_following(self): """Validate following""" value = self.cleaned_data["following"] if value is False: raise ValidationError("The value of the 'following' parameter must be true.") else: return value def clean(self): cleaned_data = super(ThreadListGetForm, self).clean() exclusive_params_count = sum( 1 for param in self.EXCLUSIVE_PARAMS if cleaned_data.get(param) ) if exclusive_params_count > 1: raise ValidationError( "The following query parameters are mutually exclusive: {}".format( ", ".join(self.EXCLUSIVE_PARAMS) ) ) return cleaned_data
def __init__(self, *args, **kwargs): commitments = kwargs.pop('commitments') super().__init__(*args, **kwargs) # print(f"FORM_KWARGS : {kwargs}") self.commitments = commitments for commitment in self.commitments: self.fields[str(commitment.pk)] = NullBooleanField( label=f"{commitment.child.nickname}, {commitment}", )
class CommentListGetForm(_PaginationForm): """ A form to validate query parameters in the comment list retrieval endpoint """ thread_id = CharField() # TODO: should we use something better here? This only accepts "True", # "False", "1", and "0" endorsed = NullBooleanField(required=False)
def test_convert_boolean(): nonnull_boolean = convert_form_field(BooleanField()) assert nonnull_boolean[0] == bool null_boolean = convert_form_field(NullBooleanField()) assert null_boolean[0] == Optional[bool]
class AddGameForm(Form): title = CharField(max_length=64) year = ChoiceField(choices=SORTED_YEARS) developer = ModelChoiceField(queryset=all_developers.order_by('name'), widget=Select) genre = ModelChoiceField(queryset=all_genres.order_by('name'), widget=Select) tags = ModelMultipleChoiceField( label=_('Tags (Select 6)'), queryset=all_tags.order_by('name'), widget=CheckboxSelectMultiple(attrs={'class': 'checkboxmultiple'})) image = ImageField(required=False) to_be_rated = NullBooleanField(label=_('Should be rated?'), required=False)
def test_convert_boolean(): nonnull_boolean = convert_form_field(BooleanField()) assert nonnull_boolean[0] == bool assert nonnull_boolean[1].field_description == "" nonnull_boolean_with_desc = convert_form_field( BooleanField(help_text="eeeeeeeeeeeeeeewwwwwwww")) assert nonnull_boolean_with_desc[0] == bool assert nonnull_boolean_with_desc[ 1].field_description == "eeeeeeeeeeeeeeewwwwwwww" null_boolean = convert_form_field(NullBooleanField()) assert null_boolean[0] == Optional[bool] assert null_boolean[1].field_description == "" null_boolean_with_desc = convert_form_field( NullBooleanField(help_text="aaaaaaaaaaaaaaaaaaawwwwwwwww")) assert null_boolean_with_desc[0] == Union[bool, None] assert null_boolean_with_desc[ 1].field_description == "aaaaaaaaaaaaaaaaaaawwwwwwwww"
def __init__(self, request, filters): self.filters = filters # kwargs.pop('filters', None) super().__init__(request.POST) for filter in self.filters: field_name = filter['slug'] if filter['type'] == Attribute.TYPE_ENUM: self.fields[field_name] = MultipleChoiceField( required=False, choices=filter['choices'] ) if filter['type'] == Attribute.TYPE_SET: self.fields[field_name] = MultipleChoiceField( required=False, choices=filter['choices'] ) elif filter['type'] == Attribute.TYPE_BOOLEAN: self.fields[field_name] = NullBooleanField( required=False, ) elif filter['type'] == Attribute.TYPE_INTEGER: self.fields[field_name + '--min'] = IntegerField( required=False, min_value=filter['range_min'], max_value=filter['range_max'], ) self.fields[field_name + '--max'] = IntegerField( required=False, min_value=filter['range_min'], max_value=filter['range_max'], ) elif filter['type'] == Attribute.TYPE_FLOAT: self.fields[field_name + '--min'] = FloatField( required=False, localize=False, min_value=filter['range_min'], max_value=filter['range_max'], ) self.fields[field_name + '--max'] = FloatField( required=False, localize=False, min_value=filter['range_min'], max_value=filter['range_max'], ) elif filter['type'] == Attribute.TYPE_STRING: self.fields[field_name] = CharField( required=False, )
class WorkForm(ModelForm): """Custom form for :class:`.models.Work`. Calculate values for readonly field version_type.""" class Meta: model = Work fields = ['title', 'iswc', 'original_title', 'library_release'] version_type = NullBooleanField( widget=Select(choices=((None, ''), (True, 'Modification'), (False, 'Original Work'))), disabled=True, required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['version_type'].initial = self.instance.is_modification()
def list(self, request, *args, **kwargs): # Without filters return empty list response if not request.query_params: return Response([]) # Condition for child list-view if NullBooleanField().to_python(request.query_params.get(CHILDREN_FILTER_KEY)): result = [] try: # SQL optimization for increase render performance with connection.cursor() as cursor: cursor.execute(CHILDREN_SQL, self.get_parent_object_kwargs(request)) for row, in cursor: result.append(row) except (Comment.MultipleObjectsReturned, Comment.DoesNotExist): result = [] return Response(result) return super().list(request, *args, **kwargs)
class AllFieldTypesForm(Form): char = CharField() int_ = IntegerField() date = DateField() time = TimeField() datetime_ = DateTimeField() regex = RegexField(regex='^[a-f]{3}$') email = EmailField() file = FileField() # image = ImageField() url = URLField() bool = BooleanField() nullbool = NullBooleanField() choice = ChoiceField(choices=(('test choice', 'yay test choice'), )) multichoice = MultipleChoiceField(choices=( ('test choice', 'yay test choice'), ('test choice 2', 'yay another choice'), ('test choice 3', 'yay test choice'), )) float = FloatField() decimal = DecimalField() ip = IPAddressField() generic_ip = GenericIPAddressField() filepath = FilePathField(path=tempfile.gettempdir(), allow_files=True, allow_folders=True) slug = SlugField() typed_choice = TypedChoiceField(choices=( (1, 'test'), (2, 'test 2'), (3, 'bah'), ), coerce=int) typed_multichoice = TypedMultipleChoiceField(choices=( (1, 'test'), (2, 'test 2'), (3, 'bah'), ), coerce=int) model_choice = ModelChoiceField(queryset=get_user_model().objects.all()) model_multichoice = ModelMultipleChoiceField( queryset=get_user_model().objects.all())
class ThreadListGetForm(_PaginationForm): """ A form to validate query parameters in the thread list retrieval endpoint """ EXCLUSIVE_PARAMS = ["topic_id", "text_search", "following"] course_id = CharField() topic_id = TopicIdField(required=False) text_search = CharField(required=False) following = NullBooleanField(required=False) def clean_course_id(self): """Validate course_id""" value = self.cleaned_data["course_id"] try: return CourseLocator.from_string(value) except InvalidKeyError: raise ValidationError( "'{}' is not a valid course id".format(value)) def clean_following(self): """Validate following""" value = self.cleaned_data["following"] if value is False: raise ValidationError( "The value of the 'following' parameter must be true.") else: return value def clean(self): cleaned_data = super(ThreadListGetForm, self).clean() exclusive_params_count = sum(1 for param in self.EXCLUSIVE_PARAMS if cleaned_data.get(param)) if exclusive_params_count > 1: raise ValidationError( "The following query parameters are mutually exclusive: {}". format(", ".join(self.EXCLUSIVE_PARAMS))) return cleaned_data
def test_nullbooleanfield_changed(self): f = NullBooleanField() self.assertTrue(f.has_changed(False, None)) self.assertTrue(f.has_changed(None, False)) self.assertFalse(f.has_changed(None, None)) self.assertFalse(f.has_changed(False, False)) self.assertTrue(f.has_changed(True, False)) self.assertTrue(f.has_changed(True, None)) self.assertTrue(f.has_changed(True, False)) # HiddenInput widget sends string values for boolean but doesn't clean them in value_from_datadict self.assertFalse(f.has_changed(False, 'False')) self.assertFalse(f.has_changed(True, 'True')) self.assertFalse(f.has_changed(None, '')) self.assertTrue(f.has_changed(False, 'True')) self.assertTrue(f.has_changed(True, 'False')) self.assertTrue(f.has_changed(None, 'False'))
def test_nullbooleanfield_clean(self): f = NullBooleanField() self.assertIsNone(f.clean('')) self.assertTrue(f.clean(True)) self.assertFalse(f.clean(False)) self.assertIsNone(f.clean(None)) self.assertFalse(f.clean('0')) self.assertTrue(f.clean('1')) self.assertIsNone(f.clean('2')) self.assertIsNone(f.clean('3')) self.assertIsNone(f.clean('hello')) self.assertTrue(f.clean('true')) self.assertFalse(f.clean('false'))
class TestForm(Form): template_name = "forms_tests/use_fieldset.html" field = NullBooleanField(widget=self.widget)
class HiddenNullBooleanForm(Form): hidden_nullbool1 = NullBooleanField(widget=HiddenInput, initial=True) hidden_nullbool2 = NullBooleanField(widget=HiddenInput, initial=False)
def test_nullbooleanfield_clean(self): f = NullBooleanField() self.assertIsNone(f.clean("")) self.assertTrue(f.clean(True)) self.assertFalse(f.clean(False)) self.assertIsNone(f.clean(None)) self.assertFalse(f.clean("0")) self.assertTrue(f.clean("1")) self.assertIsNone(f.clean("2")) self.assertIsNone(f.clean("3")) self.assertIsNone(f.clean("hello")) self.assertTrue(f.clean("true")) self.assertFalse(f.clean("false"))
class GastroSubmitForm(ModelForm): opening_mon = TimeField(required=False) opening_tue = TimeField(required=False) opening_wed = TimeField(required=False) opening_thu = TimeField(required=False) opening_fri = TimeField(required=False) opening_sat = TimeField(required=False) opening_sun = TimeField(required=False) closing_mon = TimeField(required=False) closing_tue = TimeField(required=False) closing_wed = TimeField(required=False) closing_thu = TimeField(required=False) closing_fri = TimeField(required=False) closing_sat = TimeField(required=False) closing_sun = TimeField(required=False) delivery = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) organic = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) handicapped_accessible = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) handicapped_accessible_wc = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) dog = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) child_chair = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) catering = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) wlan = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) gluten_free = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) breakfast = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) brunch = NullBooleanField( widget=Select(choices=NULLBOOLEAN_CHOICE), initial=NULLBOOLEAN_NULL, required=False, ) restaurant = BooleanField(initial=False, required=False) imbiss = BooleanField(initial=False, required=False) eiscafe = BooleanField(initial=False, required=False) cafe = BooleanField(initial=False, required=False) bar = BooleanField(initial=False, required=False) seats_indoor = IntegerField(min_value=0, initial=0) seats_outdoor = IntegerField(min_value=0, initial=0) class Meta: model = BaseLocation fields = [ "name", "street", "postal_code", "city", "latitude", "longitude", "telephone", "website", "email", "opening_mon", "closing_mon", "opening_tue", "closing_tue", "opening_wed", "closing_wed", "opening_thu", "closing_thu", "opening_fri", "closing_fri", "opening_sat", "closing_sat", "opening_sun", "closing_sun", "vegan", "comment", "comment_english", "comment_opening_hours", "comment_public_transport", "handicapped_accessible", "handicapped_accessible_wc", "dog", "child_chair", "catering", "delivery", "organic", "wlan", "gluten_free", "breakfast", "brunch", "seats_outdoor", "seats_indoor", "restaurant", "imbiss", "eiscafe", "cafe", "bar", "submit_email", ] def __init__(self, *args, **kwargs): super(GastroSubmitForm, self).__init__(*args, **kwargs) self.fields["latitude"].widget = HiddenInput() self.fields["longitude"].widget = HiddenInput() self.fields["city"].widget.attrs["readonly"] = True self.fields["postal_code"].widget = NumberInput(attrs={"maxlength": 5}) open = [ "opening_mon", "opening_tue", "opening_wed", "opening_thu", "opening_fri", "opening_sat", "opening_sun", ] close = [ "closing_mon", "closing_tue", "closing_wed", "closing_thu", "closing_fri", "closing_sat", "closing_sun", ] # change label opening for o in open: self.fields[o].label = _("Opens at") self.fields[o].widget.attrs.update( {"data-picker": "timepicker-opens"}) # change label closing for c in close: self.fields[c].label = _("Closes at") self.fields[c].widget.attrs.update( {"data-picker": "timepicker-closes"}) # add timepicker and format hh:mm timepicker = open + close for t in timepicker: self.fields[t].widget.attrs.update({"placeholder": "HH:MM"}) self.fields[t].widget.format = "%H:%M" def save(self, commit=True): self.instance.type = LocationTypeChoices.GASTRO with transaction.atomic(): instance = super(GastroSubmitForm, self).save(commit=True) self._save_opening_hours(instance=instance) self._save_tags(instance=instance) self._save_attrs( instance=instance, attr_keys=dict(GASTRO_POSITIVE_INTEGER_ATTRIBUTE_CHOICES), attr_model=PositiveIntegerAttribute, attr_manager="positive_integer_attributes", ) self._save_attrs( instance=instance, attr_keys=dict(GASTRO_BOOLEAN_ATTRIBUTE_CHOICES), attr_model=BooleanAttribute, attr_manager="boolean_attributes", ) return instance def _save_opening_hours(self, instance: BaseLocation): OPENING_HOURS_PAIRS = { WeekdayChoices.MONDAY: ("opening_mon", "closing_mon"), WeekdayChoices.TUESDAY: ("opening_tue", "closing_tue"), WeekdayChoices.WEDNESDAY: ("opening_wed", "closing_wed"), WeekdayChoices.THURSDAY: ("opening_thu", "closing_thu"), WeekdayChoices.FRIDAY: ("opening_fri", "closing_fri"), WeekdayChoices.SATURDAY: ("opening_sat", "closing_sat"), WeekdayChoices.SUNDAY: ("opening_sun", "closing_sun"), } opening_hours = [] for day, day_keys in OPENING_HOURS_PAIRS.items(): opening_hours.append( OpeningHours( location=instance, weekday=day, opening=self.cleaned_data[day_keys[0]], closing=self.cleaned_data[day_keys[1]], )) OpeningHours.objects.bulk_create(opening_hours) def _save_tags(self, instance: BaseLocation): TAGS_SET = { "restaurant": "restaurant", "imbiss": "snack bar", "eiscafe": "ice cream parlor", "cafe": "cafe", "bar": "bar", } tags: List[Tag] = [] for form_field, tag_name in TAGS_SET.items(): tag = self.cleaned_data[form_field] if tag: tags.append(Tag.objects.get_or_create(tag=tag_name)[0]) instance.tags.set(tags) def _save_attrs( self, instance: BaseLocation, attr_keys: Dict[str, str], attr_model: Type[Union[PositiveIntegerAttribute, BooleanAttribute]], attr_manager: str, ): attrs: List[attr_model] = [] for attr_key in attr_keys: attr_value = self.cleaned_data[attr_key] attrs.append( attr_model.objects.get_or_create(name=attr_key, state=attr_value)[0]) getattr(instance, attr_manager).set(attrs)