Database API
A quick walkthrough of the barangay Database API for browsing, searching, validating, and exporting Philippine geographic data.
Installation
See Get Started — Installation. Quick one-liner:
pip install barangay1. 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) # TongmagengIf 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
1print(brgy.parent) # <municipality: Sitangkai (1907005000)>
2for ancestor in brgy.ancestors:
print(repr(ancestor))
# <municipality: Sitangkai (1907005000)>
# <province: Tawi-Tawi (1907000000)>
# <region: Bangsamoro Autonomous Region In Muslim Mindanao (BARMM) (1900000000)>- 1
-
.parentreturns the direct parent record (here, the municipality). The resolved-name properties (.region,.province,.municipality) are shortcuts derived from the same hierarchy walk. - 2
-
.ancestorswalks all the way to the root, from nearest parent outward.
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)>Prefer .get(psgc_id=...) / .lookup(psgc_id) over name-based lookups when you have a code. Names like “San Jose” match hundreds of records; a PSGC ID always resolves to exactly one.
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', 'highly_urbanized_city', 'independent_component_city',
# 'component_city', 'municipality', 'submunicipality',
# 'special_geographic_area', 'barangay']
print(df.shape) # (42010, 15)
data = barangays.to_dicts()
print(len(data)) # 42010
print(data[0])
# {'name': 'Arco', 'type': 'barangay', 'psgc_id': '1900702001', ...}Each record includes six base fields (name, type, psgc_id, parent_psgc_id, nicknames, extensions) plus nine resolved hierarchy fields (region, province, highly_urbanized_city, independent_component_city, component_city, municipality, submunicipality, special_geographic_area, barangay) for immediate use in analysis. See the Database reference for the full column list.
5. Fuzzy Search
Search with fuzzy matching, returning typed SearchResult objects:
from barangay import search_fuzzy
results = search_fuzzy("Tongmageng", threshold=60.0, limit=5)
for r in results:
print(f"{r.name} ({r.psgc_id}) — score: {r.score}")
# Tongmageng (1907005010) — score: 100.0
# Itomang (0501611007) — score: 70.58823529411764
# Tongsengal (1900705025) — score: 70.0
# Tenga-tenga (1705310017) — score: 70.0
# Tonggasang (0906608017) — score: 70.0Each 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, Sitangkai, Tawi-Tawi")
print(v.valid, v.matched_name, v.score) # True Tongmageng 100.0Validate multiple addresses at once:
results = validate_many([
"Tongmageng, Sitangkai, 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, Sitangkai, Tawi-Tawi' -> valid
# 'Brgy 291, City of Manila' -> invalid
# 'Nonexistent Place' -> invalidThe 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) # False None7. 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://.../learn/database-api.html#handling-errorsMultipleResultsError — 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://.../learn/database-api.html#handling-errorsHow 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 city (City of Manila is a highly urbanized city,
# so filter on highly_urbanized_city instead of municipality)
san_jose_in_qc = [
rec for rec in barangays
if rec.name == "San Jose" and rec.highly_urbanized_city == "Quezon City"
]
for rec in san_jose_in_qc:
print(rec) # <barangay: San Jose (1381300100)>
# 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
- Database reference — full documentation of all Database API methods
- Address Validation — deep dive into validation techniques
- Bulk Barangay Lookup — batch processing at scale
- Plugins — enriching data with plugins