Repository URL to install this package:
Version:
0.1.0a0 ▾
|
dj-address
/
models.py
|
---|
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