form definition dictionary keys must be the field names now; refactoring in the Form class

This commit is contained in:
Daniil Fajnberg 2021-12-31 01:41:14 +01:00
parent 7618f6650e
commit 314b287ac4

View File

@ -69,6 +69,29 @@ class FormField:
class Form: class Form:
@staticmethod
def fields_from_dict(definition: Dict[str, Optional[dict]]) -> Dict[str, FormField]:
"""
Takes a dictionary defining form fields and creates `FormFields` objects from it.
Every key in `definition` is interpreted as the field's name.
The corresponding value can be `None` or a dictionary that can be unpacked into the FormField constructor call
alongside the name.
The special key `alias` in a field's dictionary is also allowed. If it is present, the corresponding value
will be used as the key in the output dictionary; otherwise the field's name is used as the key.
The constructed `FormField` objects are the values in the output dictionary.
"""
field_dict = {}
for name, field_def in definition.items():
if field_def is None:
field_def = {}
if isinstance(field_def, dict):
alias = field_def.pop('alias', name)
field_dict[alias] = FormField(name, **field_def)
else:
raise TypeError("Field definitions must be either dictionaries or `None`")
return field_dict
def __init__(self, definition: Dict[str, Dict], full_payload: bool = True, url: str = None): def __init__(self, definition: Dict[str, Dict], full_payload: bool = True, url: str = None):
""" """
Creates a form instance from a definition dictionary. Each element in the dictionary must define a field. Creates a form instance from a definition dictionary. Each element in the dictionary must define a field.
@ -85,7 +108,7 @@ class Form:
url (optional): url (optional):
Can be set in advance to the url that requests using this form's payload should be made to. Can be set in advance to the url that requests using this form's payload should be made to.
""" """
self.fields: Dict[str, FormField] = {alias: FormField(**field_def) for alias, field_def in definition.items()} self.fields: Dict[str, FormField] = self.fields_from_dict(definition)
self.full_payload_always: bool = full_payload self.full_payload_always: bool = full_payload
self.url: Optional[str] = url self.url: Optional[str] = url
@ -107,8 +130,10 @@ class Form:
Args: Args:
kwargs (optional): kwargs (optional):
Every key must correspond to a key in the internal dictionary of fields; Every key must correspond to an alias or name of a field in the internal dictionary of fields;
otherwise that key-value-pair is ignored. otherwise that key-value-pair is ignored.
If both a field's alias and name are different and both are present as keys in `kwargs`,
the alias-key takes precedence.
Values will be passed into the payload (if they pass validation). Values will be passed into the payload (if they pass validation).
Select fields with predefined options will only allow one of the options to be passed. Select fields with predefined options will only allow one of the options to be passed.
If `None` is passed as a value, the corresponding field's default value will be used in the payload. If `None` is passed as a value, the corresponding field's default value will be used in the payload.
@ -117,15 +142,15 @@ class Form:
Validated name-value-mapping to be used for HTTP requests from the form's fields. Validated name-value-mapping to be used for HTTP requests from the form's fields.
""" """
payload = {} payload = {}
for key, field in self.fields.items(): for alias, field in self.fields.items():
if key in kwargs.keys(): if alias in kwargs.keys():
value = kwargs[key] value = kwargs[alias]
if value is None: payload[field.name] = field.default if value is None else field.clean(value)
payload[field.name] = field.default elif alias != field.name and field.name in kwargs.keys():
else: value = kwargs[field.name]
payload[field.name] = field.clean(value) payload[field.name] = field.default if value is None else field.clean(value)
elif field.required: elif field.required:
raise ValueError(f"`{key}` is a required field, but no argument was passed.") raise ValueError(f"`{alias}` is a required field, but no argument was passed.")
elif self.full_payload_always: elif self.full_payload_always:
payload[field.name] = field.default payload[field.name] = field.default
return payload return payload