@@ -611,6 +611,7 @@ class SetPasswordField(PasswordField):
611611# source file continues from here with a few more good forms examples
612612```
613613
614+
614615## Example 3 from heritagesites
615616[ heritagesites] ( https://github.com/Michael-Cantley/heritagesites ) is a
616617[ Django] ( /django.html ) web application with a [ MySQL] ( /mysql.html )
@@ -640,3 +641,96 @@ from heritagesites.models import HeritageSite
640641~~ self .helper.form_method = ' post'
641642~~ self .helper.add_input(Submit(' submit' , ' submit' ))
642643```
644+
645+
646+ ## Example 4 from edX
647+ [ edX] ( https://github.com/edx )
648+ ([ project website] ( https://open.edx.org/ ) )
649+ is an open source platform for teaching online courses that is widely
650+ used in academia and industry. The platform code is available under the
651+ [ GNU Affero General Public License v3.0] ( https://github.com/edx/edx-platform/blob/master/LICENSE ) .
652+
653+ [ ** edx-platform/openedx/core/djangoapps/util/forms.py** ] ( "https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/util/forms.py )
654+
655+ ``` python
656+ from __future__ import absolute_import
657+
658+ from django.core.exceptions import ValidationError
659+ ~~ from django.forms import Field, MultipleHiddenInput, NullBooleanField, Select
660+
661+
662+ ~~ class MultiValueField (Field ):
663+ """
664+ Field class that supports a set of values for a single form field.
665+ The field input can be specified as:
666+ 1. a comma-separated-list (foo:bar1,bar2,bar3), or
667+ 2. a repeated field in a MultiValueDict (foo:bar1, foo:bar2, foo:bar3)
668+ 3. a combination of the above (foo:bar1,bar2, foo:bar3)
669+ Note that there is currently no way to pass a value that includes a comma.
670+ The resulting field value is a python set of the values as strings.
671+ """
672+ ~~ widget = MultipleHiddenInput
673+
674+ ~~ def to_python (self , list_of_string_values ):
675+ """
676+ Convert the form input to a list of strings
677+ """
678+ ~~ values = super (MultiValueField, self ).to_python(list_of_string_values) or set ()
679+
680+ ~~ if values:
681+ # combine all values if there were multiple specified individually
682+ ~~ values = ' ,' .join(values)
683+
684+ # parse them into a set
685+ ~~ values = set (values.split(' ,' )) if values else set ()
686+
687+ ~~ return values
688+
689+ ~~ def validate (self , values ):
690+ """
691+ Ensure no empty values were passed
692+ """
693+ ~~ if values and " " in values:
694+ ~~ raise ValidationError(" This field cannot be empty." )
695+
696+
697+ ~~ class ExtendedNullBooleanField (NullBooleanField ):
698+ """
699+ A field whose valid values are None, True, 'True', 'true', '1',
700+ False, 'False', 'false' and '0'.
701+ """
702+
703+ NULL_BOOLEAN_CHOICES = (
704+ (None , " " ),
705+ (True , True ),
706+ (True , " True" ),
707+ (True , " true" ),
708+ (True , " 1" ),
709+ (False , False ),
710+ (False , " False" ),
711+ (False , " false" ),
712+ (False , " 0" ),
713+ )
714+
715+ ~~ widget = Select(choices = NULL_BOOLEAN_CHOICES )
716+
717+ ~~ def to_python (self , value ):
718+ ~~ return to_bool(value)
719+
720+
721+ def to_bool (value ):
722+ """
723+ Explicitly checks for the string 'True', 'False', 'true',
724+ 'false', '1' and '0' and returns boolean True or False.
725+ Returns None if value is not passed at all and raises an
726+ exception for any other value.
727+ """
728+ if value in (True , ' True' , ' true' , ' 1' ):
729+ return True
730+ elif value in (False , ' False' , ' false' , ' 0' ):
731+ return False
732+ elif not value:
733+ return None
734+ else :
735+ raise ValidationError(" Invalid Boolean Value." )
736+ ```
0 commit comments