Django app wrapping edne-correios-loader for CEP lookup via ORM
Project description
django-edne-cep
Enables CEP (Código de Endereçamento Postal, Brazilian postal code) lookups in your Django app backed by a local database. Uses edne-correios-loader to populate the database from Correios eDNE data, eliminating any dependency on external APIs.
- Local database lookups, no external API calls, no network latency
- Cache with stampede protection (sentinel-based, caches not-found results too)
- Form field with CEP format validation and automatic address lookup
- Django admin integration (opt-in)
- Configurable table names, database alias, and cache backend
HTMX-powered CEP lookup in the example app
Django admin showing CEP data
Quick Start
Step 1: Install
pip install django-edne-cep
Step 2: Add to INSTALLED_APPS
INSTALLED_APPS = [
...
"django_edne_cep",
]
Step 3: Load CEP data
python manage.py load_edne_cep --auto-download
This downloads the eDNE dataset from Correios (~350 MB) and populates the local database. Subsequent runs reuse the cached file.
Use it:
from django_edne_cep import lookup_cep
cep = lookup_cep("01310-100")
if cep:
print(f"{cep.logradouro}, {cep.municipio}/{cep.uf}")
# "Avenida Paulista, São Paulo/SP"
API Reference
def lookup_cep(cep_str: str) -> Cep | None
Look up a CEP in the local database. Accepts both "01310-100" and "01310100" formats.
- Raises
ValidationErrorfor malformed input (not a valid CEP format). - Returns
Nonewhen the CEP is not found in the database (valid format, not in eDNE data). - Results are cached using the configured cache backend.
from django_edne_cep import lookup_cep
from django.core.exceptions import ValidationError
cep = lookup_cep("01310-100") # accepts "01310-100" or "01310100"
if cep:
print(f"{cep.logradouro}, {cep.municipio}/{cep.uf}")
try:
lookup_cep("ABC") # raises ValidationError for malformed input
except ValidationError:
pass
The returned Cep instance has the following fields:
cep.cep # "01310100" (8 digits, no hyphen)
cep.cep_formatado # "01310-100" (property)
cep.logradouro # str | None
cep.complemento # str | None
cep.bairro # str | None
cep.municipio # str
cep.municipio_cod_ibge # int
cep.uf # str (2 chars, e.g. "SP")
cep.nome # str | None
cep.as_dict() # dict with all fields above
CepFormField
A CharField subclass that validates CEP format and returns a Cep instance from clean().
- Accepts
"00000000"or"00000-000"input formats. - Raises
ValidationErrorwith code"cep_not_found"when the CEP is not in the database. form.cleaned_data["cep"]is aCepinstance, not a string.
from django import forms
from django_edne_cep import CepFormField
class EnderecoForm(forms.Form):
cep = CepFormField()
logradouro = forms.CharField(required=False)
municipio = forms.CharField(required=False)
# In a view:
form = EnderecoForm(request.POST)
if form.is_valid():
cep_obj = form.cleaned_data["cep"] # Cep instance
print(cep_obj.logradouro, cep_obj.municipio, cep_obj.uf)
validate_cep_format
A Django RegexValidator that accepts "00000000" and "00000-000" formats. Raises ValidationError with code "invalid_cep_format" on failure.
from django_edne_cep import validate_cep_format
validate_cep_format("01310-100") # passes silently
validate_cep_format("01310100") # passes silently
validate_cep_format("ABC") # raises ValidationError
Use it directly on any CharField or Field that should accept CEP values without triggering a database lookup.
register_admin(site: AdminSite | None = None) -> None
Registers the Cep model with a read-only CepAdmin in the given admin site. The standard use case requires no manual call. Set EDNE_CEP["ADMIN_ENABLED"] = True in Django settings instead.
register_admin() is called automatically when django_edne_cep.admin is imported with ADMIN_ENABLED=True. The explicit call is only needed for a custom AdminSite.
# Standard usage, set in Django settings:
EDNE_CEP = {
"ADMIN_ENABLED": True,
}
# Custom AdminSite usage only:
from django_edne_cep import register_admin
register_admin(site=my_custom_site)
Configuration
All settings go in the EDNE_CEP dict in your Django settings file:
EDNE_CEP = {
"CACHE_TIMEOUT": 7200,
"ADMIN_ENABLED": True,
}
| Setting | Type | Default | Description |
|---|---|---|---|
TABLE_NAMES |
dict |
see below | Override individual eDNE table names |
TABLE_SET |
str | None |
None |
Load only a subset of tables (e.g. "cep") |
EDNE_SOURCE |
str | None |
None |
Path or URL to eDNE zip file; None prompts download |
DATABASE_ALIAS |
str |
"default" |
Django database alias for CEP tables |
DATABASE_URL |
str | None |
None |
Direct database URL (overrides DATABASE_ALIAS) |
CACHE_TIMEOUT |
int |
3600 |
Cache TTL in seconds; 0 disables cache |
CACHE_ALIAS |
str |
"default" |
Django cache alias for CEP lookups |
ADMIN_ENABLED |
bool |
False |
Register CEP models in Django admin |
Default TABLE_NAMES:
TABLE_NAMES = {
"cep_unificado": "edne_cep",
"log_localidade": "edne_localidade",
"log_bairro": "edne_bairro",
"log_cpc": "edne_caixa_postal",
"log_logradouro": "edne_logradouro",
"log_grande_usuario": "edne_grande_usuario",
"log_unid_oper": "edne_unidade_operacional",
}
Override individual entries to map eDNE table names to your own table names.
Admin
Enable the read-only Django admin for CEP data:
# settings.py
EDNE_CEP = {
"ADMIN_ENABLED": True,
}
The CepAdmin registers automatically when django_edne_cep.admin is imported. It supports full-text search by CEP, street name, neighborhood, and municipality, plus filters by state (UF) and field presence.
For a custom AdminSite, call register_admin(site=my_site) explicitly after setting ADMIN_ENABLED = True.
Example App
The example/ directory contains a standalone Django project with an HTMX-powered CEP autofill form: type a CEP and the address fields fill in automatically without a page reload.
See example/README.md for full instructions on running it locally.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_edne_cep-0.1.0.tar.gz.
File metadata
- Download URL: django_edne_cep-0.1.0.tar.gz
- Upload date:
- Size: 12.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fadf09b7beeea745c5b9650b8f41484f658d3cde22170803529608a2da646250
|
|
| MD5 |
913570f1ef574a9f15e1b7bfd18430c3
|
|
| BLAKE2b-256 |
b4ab27b09e9fd7aa330b9044ff0f59f8eb27b2a36995efdb35017eafe9b3daa4
|
File details
Details for the file django_edne_cep-0.1.0-py3-none-any.whl.
File metadata
- Download URL: django_edne_cep-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17b9a98844050bb8d803775b7f2057e71d6828c3b1d6992e7da91006bc4e974b
|
|
| MD5 |
5becabe585ad7bb8f3f40d1a35eb66fd
|
|
| BLAKE2b-256 |
c0617cd999dab341007965eaf632784eba58cc14663b6fcddd1b05f3f01fa292
|