Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
dj-address / models.py
Size: Mime:
import pycountry
from building_blocks.models import KaosModel, UnnamedKaosModel
from dj_kaos_utils.models import HasAutoFields
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import UniqueConstraint, Q
from django.utils.functional import cached_property

from .querysets import *


class Country(
    HasAutoFields,
    KaosModel
):
    name = models.CharField(max_length=255, unique=True)
    alpha_2_code = models.CharField(max_length=2, blank=True)
    alpha_3_code = models.CharField(max_length=3, blank=True)
    numeric_code = models.CharField(max_length=3, blank=True)
    official_name = models.CharField(max_length=255, blank=True)
    flag = models.CharField(max_length=2, blank=True)

    class Meta:
        verbose_name_plural = "countries"

    objects = CountryQuerySet.as_manager()

    @cached_property
    def pycountry(self):
        if self.alpha_2_code:
            return pycountry.countries.get(alpha_2=self.alpha_2_code)
        if self.alpha_3_code:
            return pycountry.countries.get(alpha_3=self.alpha_3_code)
        if self.numeric_code:
            return pycountry.countries.get(numeric=self.numeric_code)
        if self.name:
            return pycountry.countries.get(name=self.name)
        if self.flag:
            return pycountry.countries.get(flag=self.flag)
        if self.official_name:
            return pycountry.countries.get(official_name=self.official_name)

    def set_auto_fields(self):
        py_country = self.pycountry
        if py_country:
            if not self.name:
                self.name = py_country.name
            if not self.alpha_2_code:
                self.alpha_2_code = py_country.alpha_2
            if not self.alpha_3_code:
                self.alpha_3_code = py_country.alpha_3
            if not self.numeric_code:
                self.numeric_code = py_country.numeric
            if not self.official_name:
                self.official_name = getattr(py_country, 'official_name', "")
            if not self.flag:
                self.flag = py_country.flag

    def clean(self):
        super().clean()
        py_country = self.pycountry
        if py_country:
            if self.alpha_2_code != py_country.alpha_2:
                raise ValidationError({
                    'alpha_2_code': f"Doesn't match the expected value: {py_country.alpha_2}"
                })
            if self.alpha_3_code != py_country.alpha_3:
                raise ValidationError({
                    'alpha_3_code': f"Doesn't match the expected value: {py_country.alpha_3}"
                })
            if self.numeric_code != py_country.numeric:
                raise ValidationError({
                    'numeric_code': f"Doesn't match the expected value: {py_country.numeric}"
                })
            official_name = getattr(py_country, 'official_name', '')
            if self.official_name != official_name:
                raise ValidationError({
                    'official_name': f"Doesn't match the expected value: {official_name}"
                })
            if self.flag != py_country.flag:
                raise ValidationError({
                    'flag': f"Doesn't match the expected value: {py_country.flag}"
                })


class CountryRegion(
    HasAutoFields,
    KaosModel
):
    country = models.ForeignKey(Country, models.CASCADE, 'regions')
    code = models.CharField(max_length=20, blank=True)

    class Meta:
        verbose_name = "region"
        constraints = [
            UniqueConstraint(fields=('country', 'code'), condition=~Q(code=''), name='unique_when_code')
        ]

    objects = RegionQuerySet.as_manager()

    def __str__(self):
        return f"{self.name}, {self.country}"


class Municipality(
    HasAutoFields,
    KaosModel
):
    region = models.ForeignKey(CountryRegion, models.CASCADE, 'municipalities')
    short_name = models.CharField(max_length=20, blank=True)

    class Meta:
        verbose_name_plural = "municipalities"

    objects = MunicipalityQuerySet.as_manager()

    def __str__(self):
        return f"{self.name}, {self.region}"


class Address(
    HasAutoFields,
    UnnamedKaosModel
):
    addressee = models.CharField(max_length=255, blank=True)
    additional_delivery_information = models.CharField(max_length=255, blank=True)
    address_1 = models.CharField(max_length=255)
    address_2 = models.CharField(max_length=255, blank=True)
    municipality = models.ForeignKey(Municipality, models.PROTECT, 'addresses',
                                     null=True, blank=True)
    postal_code = models.CharField(max_length=255, blank=True)

    _municipality_name = models.CharField(max_length=255, blank=True)
    _region_name = models.CharField(max_length=255, blank=True)
    _country_name = models.CharField(max_length=255, blank=True)

    class Meta:
        verbose_name_plural = "addresses"

    def __str__(self):
        s = self.address_1
        if self.address_2:
            s = f"{self.address_2} - {self.address_1}"
        s = f"{s}, {self._municipality_name}, {self._region_name}"
        if self.postal_code:
            s = f"{s} {self.postal_code}"
        s = f"{s}, {self._country_name}"

        if self.addressee:
            s = f"{self.addressee} ({s})"
        return s

    @property
    def postal_label(self):
        s = []
        if self.addressee:
            s.append(self.addressee)
        if self.additional_delivery_information:
            s.append(self.additional_delivery_information)
        _s = self.address_1
        if self.address_2:
            _s = f"{self.address_2} - {self.address_1}"
        s.append(_s)
        s.append(f"{self._municipality_name} {self._region_name} {self.postal_code}")
        s.append(self._country_name)
        return "\n".join(s)

    def clean(self):
        super().clean()
        if not self.municipality:
            if not self._municipality_name or not self._region_name or not self._country_name:
                raise ValidationError({
                    'municipality': "Either pick a municipality or enter a custom one in `_municipality_name`",
                    '_municipality_name': "Either pick a municipality or enter this",
                    '_region_name': "Either pick a municipality or enter this",
                    '_country_name': "Either pick a municipality or enter this",
                })

    def set_auto_fields(self):
        municipality = self.municipality
        region = municipality and municipality.region
        country = region and region.country

        if not country:
            country = Country.objects.get_by_name_or_code(self._country_name)
        if country and not region:
            region = CountryRegion.objects.get_by_name_or_code(self._region_name, country=country)
        if region and not municipality:
            municipality = Municipality.objects.get_by_name_or_code(self._municipality_name, region=region)

        if municipality:
            self.municipality = municipality
            self._municipality_name = municipality.name
        if region:
            self._region_name = region.name
        if country:
            self._country_name = country.name