A quick walkthrough of the barangay Database API for browsing, searching, validating, and exporting Philippine geographic data.

Installation

pip install barangay

1. Browse Administrative Levels

Pre-built views give you direct access to every admin level in the PSGC database:

from barangay import regions, provinces, municipalities, cities, barangays

print(regions)     # <PSGC region database: 18 records>
print(provinces)   # <PSGC province database: 82 records>
print(barangays)   # <PSGC barangay database: 42010 records>

Each view supports iteration, containment checks, and counting:

print(len(barangays))          # 42010
print("1907005010" in barangays)  # True

for region in regions:
    print(region.name)
# Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
# Cordillera Administrative Region (CAR)
# MIMAROPA Region
# ...

2. Look Up a Record

Look up a single record by name or PSGC ID:

# By name
brgy = barangays.get(name="Tongmageng")
print(brgy)  # <barangay: Tongmageng (1907005010)>

# By PSGC ID (always unique)
brgy = barangays.lookup("1907005010")
print(brgy.name)  # Tongmageng

If a name matches multiple records, get() raises MultipleResultsError. Use lookup() with a PSGC ID for guaranteed-unique lookups. See Handling Errors for full details.

3. Traverse the Hierarchy

Each record knows its position in the administrative hierarchy:

brgy = barangays.get(name="Tongmageng")

print(brgy.region)       # Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
print(brgy.province)     # Tawi-Tawi
print(brgy.municipality)  # Sitangkai
print(brgy.parent)       # <municipality: Sitangkai (1907005000)>

for ancestor in brgy.ancestors:
    print(repr(ancestor))
# <municipality: Sitangkai (1907005000)>
# <province: Tawi-Tawi (1907000000)>
# <region: Bangsamoro Autonomous Region In Muslim Mindanao (BARMM) (1900000000)>

Navigate downward with .children:

manila = cities.get(name="City of Manila")
for child in manila.children[:3]:
    print(repr(child))
# <submunicipality: Tondo I/II (1380601000)>
# <submunicipality: Binondo (1380602000)>
# <submunicipality: Quiapo (1380603000)>

4. Export to Pandas

Export any view directly to a DataFrame or list of dicts:

df = barangays.to_frame()
print(df.columns.tolist())
# ['name', 'type', 'psgc_id', 'parent_psgc_id', 'nicknames', 'extensions',
#  'region', 'province', 'municipality', 'city']
print(df.shape)  # (42010, 10)

data = barangays.to_dicts()
print(len(data))  # 42010
print(data[0])
# {'name': 'Arco', 'type': 'barangay', 'psgc_id': '1900702001', ...}

Each record includes resolved hierarchy fields (region, province, municipality, city) for immediate use in analysis.

Search with fuzzy matching, returning typed SearchResult objects:

from barangay import search_fuzzy

results = search_fuzzy("Tongmagen, Tawi-Tawi", threshold=60.0, limit=5)
for r in results:
    print(f"{r.name} ({r.psgc_id}) — score: {r.score}")
# Tongmageng (1907005010) — score: 100.0
# Tonggosong (1907004005) — score: 84.21
# Tongbangkaw (1907007042) — score: 82.05
# Tongusong (1907005012) — score: 81.08
# Tongehat (1907011014) — score: 77.78

Each result exposes .name, .psgc_id, .score, and .match_type.

6. Validate Addresses

Validate addresses against the PSGC masterlist with a high-confidence threshold:

from barangay import validate, validate_many

v = validate("Tongmageng, Tawi-Tawi")
print(v.valid, v.matched_name, v.score)  # True Tongmageng 100.0

Validate multiple addresses at once:

results = validate_many([
    "Tongmageng, Tawi-Tawi",
    "Brgy 291, City of Manila",
    "Nonexistent Place",
])
for r in results:
    status = "valid" if r.valid else "invalid"
    print(f"{r.input!r} -> {status}")
# 'Tongmageng, Tawi-Tawi' -> valid
# 'Brgy 291, City of Manila' -> invalid
# 'Nonexistent Place' -> invalid

The default threshold is 95.0. Lower it for more lenient matching:

v = validate("Brgy 291, City of Manila", threshold=80.0)
print(v.valid, v.score)  # True 88.24

7. Handling Errors

RecordNotFoundError — No match found

.get() raises RecordNotFoundError when no record matches your query:

from barangay import barangays, RecordNotFoundError

try:
    brgy = barangays.get(name="DoesNotExist")
except RecordNotFoundError as e:
    print(e)
    # No barangay with name 'DoesNotExist'.
    # See https://.../tutorials/database_api.html#handling-errors

MultipleResultsError — Multiple matches found

Some names like "San Jose" or "San Roque" appear hundreds of times across the Philippines. .get(name=...) raises MultipleResultsError when more than one record matches:

from barangay import barangays, MultipleResultsError

try:
    brgy = barangays.get(name="San Jose")
except MultipleResultsError as e:
    print(e)
    # Name 'San Jose' matched 244 records. Use psgc_id for exact lookup, or iterate.
    # See https://.../tutorials/database_api.html#handling-errors

How to resolve: Use a PSGC ID

PSGC IDs are globally unique. Use .get(psgc_id=...) for exact lookups:

brgy = barangays.get(psgc_id="1380100001")
print(brgy)  # <barangay: Barangay 1 (1380100001)>

How to resolve: Iterate and filter

When you don't have a PSGC ID, iterate the view and filter by additional criteria:

# Get all barangays named "San Jose"
matches = [rec for rec in barangays if rec.name == "San Jose"]
print(len(matches))  # 244

# Narrow down by parent
san_jose_in_manila = [
    rec for rec in barangays
    if rec.name == "San Jose" and rec.municipality == "City of Manila"
]
for rec in san_jose_in_manila:
    print(rec)  # <barangay: San Jose (1380208005)>

# Narrow down by region
san_jose_in_cavite = [
    rec for rec in barangays
    if rec.name == "San Jose" and rec.province == "Cavite"
]
for rec in san_jose_in_cavite:
    print(f"{rec.name}{rec.municipality}, {rec.province}")

How to resolve: Use lookup() for nullable lookups

If you want None instead of an exception, use .lookup():

rec = barangays.lookup("9999999999")  # returns None instead of raising
if rec is not None:
    print(rec.name)
else:
    print("Not found")

Next Steps