Skip to Content

Geo Models

Data models and DTOs for geographic data.

Database Models

Country

250 countries with metadata.

class Country(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=100) iso2 = models.CharField(max_length=2, unique=True) # "KR", "US" iso3 = models.CharField(max_length=3, null=True) # "KOR", "USA" phonecode = models.CharField(max_length=20) # "+82", "+1" capital = models.CharField(max_length=100) # "Seoul" currency = models.CharField(max_length=10) # "KRW" currency_name = models.CharField(max_length=100) # "Won" currency_symbol = models.CharField(max_length=10) # "₩" region = models.CharField(max_length=50) # "Asia" subregion = models.CharField(max_length=50) # "Eastern Asia" emoji = models.CharField(max_length=10) # "🇰🇷" latitude = models.DecimalField(...) longitude = models.DecimalField(...) is_active = models.BooleanField(default=True)

State

5,000+ states/regions/provinces.

class State(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=100) # "California", "Bali" country = models.ForeignKey(Country) iso2 = models.CharField(max_length=10) # "CA", "BA" type = models.CharField(max_length=50) # "state", "province" latitude = models.DecimalField(...) longitude = models.DecimalField(...) is_active = models.BooleanField(default=True)

City

150,000+ cities worldwide.

class City(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=100) state = models.ForeignKey(State, null=True) country = models.ForeignKey(Country) latitude = models.DecimalField(max_digits=10, decimal_places=7) longitude = models.DecimalField(max_digits=10, decimal_places=7) is_active = models.BooleanField(default=True)

DTOs (Data Transfer Objects)

Services return Pydantic DTOs for type safety and serialization.

CountryDTO

class CountryDTO(BaseModel): id: int name: str iso2: str iso3: str | None phonecode: str | None capital: str | None currency: str | None currency_name: str | None currency_symbol: str | None region: str | None subregion: str | None emoji: str | None latitude: float | None longitude: float | None

Example:

country = db.get_country("KR") country.name # "South Korea" country.iso2 # "KR" country.emoji # "🇰🇷" country.currency # "KRW" country.region # "Asia"

StateDTO

class StateDTO(BaseModel): id: int name: str country_id: int country_iso2: str | None iso2: str | None type: str | None latitude: float | None longitude: float | None

Example:

state = db.get_state(1416) state.name # "California" state.iso2 # "CA" state.country_iso2 # "US" state.type # "state"

CityDTO

class CityDTO(BaseModel): id: int name: str state_id: int | None state_name: str | None country_id: int country_iso2: str | None latitude: float longitude: float

Example:

city = db.get_city(1835848) city.name # "Seoul" city.state_name # "Seoul" city.country_iso2 # "KR" city.latitude # 37.5665 city.longitude # 126.978

LocationDTO

Full location hierarchy.

class LocationDTO(BaseModel): city: CityDTO | None state: StateDTO | None country: CountryDTO | None latitude: float | None longitude: float | None

Example:

location = resolve_location(1835848) location.city.name # "Seoul" location.state.name # "Seoul" location.country.name # "South Korea" location.country.emoji # "🇰🇷"

NearbyResult

City with distance from search point.

class NearbyResult(BaseModel): city: CityDTO distance_km: float

Example:

nearby = db.get_nearby_cities(-8.6908, 115.1688, radius_km=50) for result in nearby: print(f"{result.city.name}: {result.distance_km:.1f} km") # Denpasar: 2.3 km # Kuta: 5.1 km

Data Population

Management Command

# First-time population (downloads from GitHub) python manage.py geo_populate # Force re-download python manage.py geo_populate --force # Clear cached files python manage.py geo_populate --clear-cache

Data Source

Data from dr5hn/countries-states-cities-database :

FileSizeRecords
countries.json~330 KB250
states.json~4.4 MB5,000+
cities.json~133 MB150,000+

Files are downloaded on demand, not bundled with package.


Querying Models Directly

While services are preferred, you can query models directly:

from django_cfg.apps.tools.geo.models import Country, State, City # Get country korea = Country.objects.get(iso2="KR") # Get states in country states = State.objects.filter(country=korea) # Get cities in state cities = City.objects.filter(state__name="California") # Nearby cities (without PostGIS) from django.db.models import F from django.db.models.functions import Power, Sqrt # Approximate distance (not geodesic) cities = City.objects.annotate( distance=Sqrt( Power(F('latitude') - 37.5665, 2) + Power(F('longitude') - 126.978, 2) ) ).order_by('distance')[:10]

Note: Use GeoDatabase services for caching and proper geodesic distance calculations.


See Also

Last updated on