Added a utils.py get_states_of_brazil
All Changes
I Added a utils.py file to localflavor.br initially with a method called get_states_of_brazil. Through this method, the user can get the state through a (federative_unit - str) and can configure the return to be upper or lower case. If the federative_unit is None or if its value is not in the available state options, a dict will be returned with all states of Brazil.
-
[x ] Add an entry to the docs/changelog.rst describing the change.
-
[x ] Add an entry for your name in the docs/authors.rst file if it's not already there.
@vic012 Can you provide some information about how this fits into django-localflavor? Reading through get_states_of_brazil(), it seems to be a helper function / application specific logic, rather than something connected to a Django model or form. I don't use the Brazil locolflavor personally, so I don't know how it's useful to developers in Brazil who use the BR flavor. Thanks.
Thanks for the feedback, @benkonrath !
You're right — get_states_of_brazil() is a helper function and not directly tied to models or forms. However, its purpose is to centralize and simplify access to the list of Brazilian states already defined in STATE_CHOICES.
Why it fits into django-localflavor:
- Avoids repetition: Many Brazilian developers need to access the state name based on the UF (e.g.,
"SP"→"São Paulo"), especially when integrating form input with external APIs or when customizing templates or business logic. - Based on existing localflavor data: It reuses
STATE_CHOICES, so it stays consistent with the values already defined by the package. - Encourages best practices: Rather than copying the state list or writing their own mapping, developers can use a tested, documented utility.
- Supports common Brazilian workflows: In many Brazilian applications, returning a full list of state names or formatting them (capitalized or not) is a very common task.
Example use case:
Let’s say a user stores "RJ" in a model field and wants to display "Rio de Janeiro" in a template or a PDF report:
from localflavor.br.utils import get_states_of_brazil
print(get_states_of_brazil("RJ")) # Rio de Janeiro
# or
print(get_states_of_brazil("rj")) # Rio de Janeiro
print(get_states_of_brazil("RJ", capital_letter=True)) # RIO DE JANEIRO
# or
print(get_states_of_brazil("rj", capital_letter=True)) # RIO DE JANEIRO
print(get_states_of_brazil("Rt", capital_letter=True)) # {'AC': 'ACRE', 'AL': 'ALAGOAS', 'AP': 'AMAPÁ', ...}
# or
print(get_states_of_brazil("Rt")) # {'AC': 'Acre', 'AL': 'Alagoas', 'AP': 'Amapá', ...}
print(get_states_of_brazil(capital_letter=True)) # {'AC': 'ACRE', 'AL': 'ALAGOAS', 'AP': 'AMAPÁ', ...}
# or
print(get_states_of_brazil()) # {'AC': 'Acre', 'AL': 'Alagoas', 'AP': 'Amapá', ...}
# models.py
from django.db import models
from localflavor.br.br_states import STATE_CHOICES
class UserProfile(models.Model):
name = models.CharField(max_length=100)
state = models.CharField(max_length=2, choices=STATE_CHOICES)
# views.py
from django.shortcuts import render
from localflavor.br.utils import get_states_of_brazil
from .models import UserProfile
def profile_view(request, user_id):
profile = UserProfile.objects.get(id=user_id)
state_name = get_states_of_brazil(profile.state)
return render(request, 'profile.html', {'profile': profile, 'state_name': state_name})
{# profile.html #}
<p>User: {{ profile.name }}</p>
<p>State: {{ state_name }}</p>
Using raw STATE_CHOICES directly in a large codebase:
In large projects with multiple developers, it's common to see repetitive logic written in different parts of the codebase to convert Brazilian state abbreviations into full names using the STATE_CHOICES variable.
Here's an example of how it's typically done without a helper:
from localflavor.br.br_states import STATE_CHOICES
def get_state(federative_unit=None, capital_letter=False):
state_choices_available = {
acronym.upper(): name.upper() if capital_letter else name
for acronym, name in STATE_CHOICES
}
if federative_unit is None:
return state_choices_available
federative_unit = str(federative_unit).upper()
return state_choices_available.get(federative_unit, state_choices_available)
# or
def get_state_name(federative_unit=None, capital_letter=False):
state_dict = {
acronym.upper(): name.upper() if capital_letter else name
for acronym, name in STATE_CHOICES
}
return state_dict.get(str(federative_unit).upper(), state_dict)
Although this works, it tends to be copied and adapted differently across the project — sometimes with minor variations in casing, error handling, or naming conventions. This increases the risk of inconsistencies and makes the code harder to read, debug, and maintain over time.
By centralizing this logic in a utility function like get_states_of_brazil, we:
- Promote code reuse and avoid duplication.
- Keep logic consistent and predictable across the team.
- Make it easier to maintain and improve in a single place.
- Reduce the chance of bugs caused by inconsistent implementations.
In short, a shared utility improves readability, maintainability, and developer experience in growing codebases.
I understand that this is a basic utility and not everyone may find it necessary. However, I've personally needed a similar function in the past, and I believe this addition could be helpful to others as well. Just as localflavor has supported many applications around the world with simple but essential tools, this small contribution might prove useful in similar scenarios.
I am not sure if this function is really useful for a broader user base or something that is useful just for a few use cases. I also see some problems with this function that could be improved anyway:
- The name is not ideal.
get_states_of_brasil(states in plural) leads me to believe that I will receive a list (or at least a dictionary) with the states of Brazil. However callingget_states_of_brazil("RJ")returns me the stringRio de Janeiro. - But if I call it without arguments (
get_states_of_brazil()), the response is a dictionary generated with the contents of the existingSTATE_CHOICESlist of tuples. This is not a good design as the same function returns completely different types of information. - String processing (upper vs lower case) can be done outside the function (using Python stdlib or if the information is supposed to be presented in a Django template using upper template tag
- A better name could be
get_state_name_from_state_abbreviationwhich presents exactly the intent of it (given a state abbreviation string, return the full state name), and the implementation is very simple with some processing ofSTATE_CHOICESto convert it to a dictionary once (this could be defined as a constant and reused later)