Skip to content
Snippets Groups Projects
fields.py 1.77 KiB
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}


def flatten_data(data):
    flattened = dict()
    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
    """
    data = VALIDATION_DATA

    def clean(self, value, **kwargs):
        country = value['country']
        try:
            country_data = self.data[country]
        except KeyError:
            raise ValidationError('Invalid country selected')

        fields = flatten_data(country_data['fields'])

        missing_fields = set(country_data['required']) - set(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:
            return json.loads(value)
        except TypeError:
            return value