@@ -441,3 +441,83 @@ def compress(self, data_list):
441441 total_inches = feet * 12 + inches
442442 return int (total_inches )
443443 return None
444+
445+
446+ class ImperialWeightWidget (widgets .MultiWidget ):
447+ """
448+ A widget that splits weight into stone and pounds inputs.
449+ """
450+
451+ def __init__ (self , attrs = None ):
452+ weight_widgets = (
453+ widgets .NumberInput (attrs = attrs ),
454+ widgets .NumberInput (attrs = attrs ),
455+ )
456+ super ().__init__ (weight_widgets , attrs )
457+
458+ def decompress (self , value ):
459+ """
460+ Convert total pounds back to stone and pounds for display.
461+ """
462+ if value :
463+ stone = int (value // 14 )
464+ pounds = value % 14
465+ return [stone , pounds ]
466+ return [None , None ]
467+
468+ def subwidgets (self , name , value , attrs = None ):
469+ """
470+ Expose data for each subwidget, so that we can render them separately in the template.
471+ """
472+ context = self .get_context (name , value , attrs )
473+ for subwidget in context ["widget" ]["subwidgets" ]:
474+ yield subwidget
475+
476+
477+ class ImperialWeightField (forms .MultiValueField ):
478+ """
479+ A field that combines stone and pounds into a single weight value in total pounds.
480+ """
481+
482+ widget = ImperialWeightWidget
483+
484+ def __init__ (self , * args , ** kwargs ):
485+ error_messages = kwargs .get ("error_messages" , {})
486+
487+ stone_kwargs = {
488+ "min_value" : 0 ,
489+ "max_value" : 50 ,
490+ "error_messages" : {
491+ 'invalid' : 'Stone must be in whole numbers.' ,
492+ 'min_value' : 'Weight must be between 4 stone and 50 stone.' ,
493+ 'max_value' : 'Weight must be between 4 stone and 50 stone.' ,
494+ ** error_messages ,
495+ },
496+ }
497+ pounds_kwargs = {
498+ "min_value" : 0 ,
499+ "max_value" : 13 ,
500+ "error_messages" : {
501+ 'invalid' : 'Pounds must be in whole numbers.' ,
502+ 'min_value' : 'Pounds must be between 0 and 13.' ,
503+ 'max_value' : 'Pounds must be between 0 and 13.' ,
504+ ** error_messages ,
505+ },
506+ }
507+ fields = (
508+ IntegerField (** stone_kwargs ),
509+ IntegerField (** pounds_kwargs ),
510+ )
511+ kwargs ["template_name" ] = "forms/imperial-weight-input.jinja"
512+
513+ super ().__init__ (fields , * args , ** kwargs )
514+
515+ def compress (self , data_list ):
516+ """
517+ Convert stone and pounds to total pounds.
518+ """
519+ if data_list and all (item is not None for item in data_list ):
520+ stone , pounds = data_list
521+ total_pounds = stone * 14 + pounds
522+ return int (total_pounds )
523+ return None
0 commit comments