Newer
Older
import json
from os import path
from django import forms
from django.core.exceptions import ValidationError
from .widgets import AddressWidget
basepath = path.dirname(__file__)
filepath = path.abspath(path.join(basepath, "static", "addressfield.min.json"))
with open(filepath, encoding="utf8") as address_data:
countries = json.load(address_data)["options"]
VALIDATION_DATA = {country["iso"]: country for country in countries}
"thoroughfare",
"premise",
"localityname",
"administrativearea",
"postalcode",
"country",
def flatten_data(data):
flattened = {}
for d in data:
for k, v in d.items():
if isinstance(v, list):
value = flatten_data(v)
else:
value = {k: v}
flattened.update(value)
return flattened
class AddressField(forms.CharField):
"""
The field stores the address in a flattened form,
so the locality components are on the same level as country or premise
"""
widget = AddressWidget
def clean(self, value, **kwargs):
country = value["country"]
except KeyError:
raise ValidationError("Invalid country selected") from None
fields = flatten_data(country_data["fields"])
missing_fields = set(country_data["required"]) - {
field for field, value in value.items() if value
}
if missing_fields:
missing_field_name = [fields[field]["label"] for field in missing_fields]
raise ValidationError(
"Please provide data for: {}".format(", ".join(missing_field_name))
)
return super().clean(value, **kwargs)
def to_python(self, value):
return json.dumps(value)
def prepare_value(self, value):
try:
# Handle empty value with "or".
return json.loads(value or {})
except TypeError:
return value