Skip to content
Snippets Groups Projects
fields.py 1.77 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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