Customization¶
Customize the Country List¶
Country names are taken from the official ISO 3166-1 list, with some country names being replaced with their more common usage (such as "Bolivia" instead of "Bolivia, Plurinational State of"). See ISO 3166-1 Country Name Formatting for details on the official naming conventions and quirks.
Use Official ISO Names¶
To retain the official ISO 3166-1 naming for all fields, set the COUNTRIES_COMMON_NAMES setting to False:
Override Specific Countries¶
If your project requires the use of alternative names, the inclusion or exclusion of specific countries, set the COUNTRIES_OVERRIDE setting to a dictionary of names which override the defaults.
Note
You will need to handle translation of customized country names.
Setting a country's name to None will exclude it from the country list. For example:
from django.utils.translation import gettext_lazy as _
COUNTRIES_OVERRIDE = {
"NZ": _("Middle Earth"),
"AU": None, # Exclude Australia
"US": {
"names": [
_("United States of America"),
_("America"),
],
},
}
Limit to Specific Countries¶
If you have a specific list of countries that should be used, use COUNTRIES_ONLY:
Or to specify your own country names, use a dictionary or two-tuple list (string items will use the standard country name):
from django.utils.translation import gettext_lazy as _
COUNTRIES_ONLY = [
"US",
"GB",
("NZ", _("Middle Earth")),
("AU", _("Desert")),
]
Dynamic Country Ordering¶
For language-based ordering, automatic locale detection, and showing certain countries first, see the Dynamic Ordering Guide.
Quick example of static first countries:
COUNTRIES_FIRST = ["US", "GB", "CA"] # Show these countries first
COUNTRIES_FIRST_SORT = True # Sort them alphabetically
COUNTRIES_FIRST_REPEAT = True # Repeat in main list
COUNTRIES_FIRST_BREAK = "───────────" # Add separator
The Dynamic Ordering guide covers:
- Static ordering -
COUNTRIES_FIRSTand related settings - Language-based ordering - Show different countries first based on user's language
- Auto-detection - Automatically prioritize user's country from locale
- Programmatic control - Use
countries_context()for per-request customization
Customize the Flag URL¶
The COUNTRIES_FLAG_URL setting can be used to set the URL for the flag image assets. It defaults to:
The URL can be relative to the STATIC_URL setting, or an absolute URL.
The location is parsed using Python's string formatting and is passed the following arguments:
code- lowercase country codecode_upper- uppercase country code
For example:
Note
No checking is done to ensure that a static flag actually exists.
Per-Field Flag URL¶
Alternatively, you can specify a different URL on a specific CountryField:
from django.db import models
from django_countries.fields import CountryField
class Person(models.Model):
name = models.CharField(max_length=100)
country = CountryField(
countries_flag_url="//flags.example.com/{code}.png"
)
Single Field Customization¶
To customize an individual field rather than rely on project-level settings, create a Countries subclass which overrides settings.
To override a setting, give the class an attribute matching the lowercased setting without the COUNTRIES_ prefix.
Then just reference this class in a field. For example, this CountryField uses a custom country list that only includes the G8 countries:
from django.db import models
from django.utils.translation import gettext_lazy as _
from django_countries import Countries
from django_countries.fields import CountryField
class G8Countries(Countries):
only = [
"CA", "FR", "DE", "IT", "JP", "RU", "GB",
("EU", _("European Union"))
]
class Vote(models.Model):
country = CountryField(countries=G8Countries)
approve = models.BooleanField()
Available Settings for Customization¶
When creating a custom Countries subclass, you can override these settings (without the COUNTRIES_ prefix):
only- Equivalent toCOUNTRIES_ONLYoverride- Equivalent toCOUNTRIES_OVERRIDEfirst- Equivalent toCOUNTRIES_FIRSTfirst_repeat- Equivalent toCOUNTRIES_FIRST_REPEATfirst_sort- Equivalent toCOUNTRIES_FIRST_SORTfirst_break- Equivalent toCOUNTRIES_FIRST_BREAKflag_url- Equivalent toCOUNTRIES_FLAG_URLcommon_names- Equivalent toCOUNTRIES_COMMON_NAMES
Temporary Context-Based Customization¶
New in version 8.2.0
For per-request or temporary overrides (such as in views or middleware), use the countries_context() context manager. This allows you to temporarily override any country option without modifying global settings or creating custom subclasses.
Basic Usage¶
from django_countries import countries_context
def checkout_view(request):
# Temporarily override settings for this request
with countries_context(first=['US', 'CA']):
form = CheckoutForm()
return render(request, 'checkout.html', {'form': form})
Available Options¶
countries_context() supports all country configuration options:
first- List of countries to show firstonly- Limit to specific countriesfirst_sort- Sort first countries alphabeticallyfirst_repeat- Repeat first countries in main listfirst_break- Separator text between first and main listfirst_by_language- Language-based country ordering mappingfirst_auto_detect- Auto-detect country from locale
How options work:
Each option independently overrides its corresponding setting. For example:
- first overrides COUNTRIES_FIRST
- first_by_language overrides COUNTRIES_FIRST_BY_LANGUAGE
- first_auto_detect overrides COUNTRIES_FIRST_AUTO_DETECT
To disable a language-based mapping for a specific request, explicitly set it to an empty dict:
# With COUNTRIES_FIRST_BY_LANGUAGE = {'fr': ['FR', 'CH']} in settings
with countries_context(first=['US', 'CA'], first_by_language={}):
form = MyForm() # Uses US, CA (not FR, CH) even for French users
Common Use Cases¶
User preferences:
def profile_view(request):
if request.user.is_authenticated:
preferred = request.user.profile.favorite_countries
else:
preferred = []
with countries_context(first=preferred):
form = ProfileForm()
return render(request, 'profile.html', {'form': form})
Regional restrictions:
def regional_signup(request):
# Only show North American countries
with countries_context(only=['US', 'CA', 'MX'], first=['US']):
form = SignupForm()
return render(request, 'signup.html', {'form': form})
IP-based geolocation (via middleware):
from django_countries import countries_context
import geoip2.database
class GeolocationMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.reader = geoip2.database.Reader('/path/to/GeoLite2-Country.mmdb')
def __call__(self, request):
# Detect country from IP
try:
response = self.reader.country(request.META['REMOTE_ADDR'])
detected_country = [response.country.iso_code]
except Exception:
detected_country = []
# Apply for all forms in this request
with countries_context(first=detected_country):
return self.get_response(request)
Sorting options:
def sorted_countries_view(request):
# Show first countries alphabetically
with countries_context(first=['US', 'GB', 'AU'], first_sort=True):
form = MyForm() # Shows: AU, GB, US (sorted)
return render(request, 'form.html', {'form': form})
Nested Contexts¶
Contexts can be nested, with the innermost context taking precedence:
with countries_context(first=['US', 'CA']):
form1 = MyForm() # US, CA first
with countries_context(first=['FR', 'DE']):
form2 = MyForm() # FR, DE first (overrides outer context)
form3 = MyForm() # Back to US, CA first
Priority¶
Each option in countries_context() independently overrides its corresponding setting with the highest priority:
| Context Option | Overrides (in order) |
|---|---|
first |
Custom Countries.first → COUNTRIES_FIRST |
first_by_language |
Custom Countries.first_by_language → COUNTRIES_FIRST_BY_LANGUAGE |
first_auto_detect |
Custom Countries.first_auto_detect → COUNTRIES_FIRST_AUTO_DETECT |
only |
Custom Countries.only → COUNTRIES_ONLY |
first_sort |
Custom Countries.first_sort → COUNTRIES_FIRST_SORT |
first_repeat |
Custom Countries.first_repeat → COUNTRIES_FIRST_REPEAT |
first_break |
Custom Countries.first_break → COUNTRIES_FIRST_BREAK |
Important: Options work independently. Setting first in the context does not automatically disable COUNTRIES_FIRST_BY_LANGUAGE. To disable language-based ordering, explicitly set first_by_language={}:
# Language-based ordering still applies
with countries_context(first=['US']):
pass # French users still see FR, CH, BE, LU (from BY_LANGUAGE)
# Language-based ordering disabled
with countries_context(first=['US'], first_by_language={}):
pass # All users see US first
This explicit design makes it ideal for request-specific customization where you need precise control over which settings to override.
Thread-safe
countries_context() uses thread-local storage, making it safe to use in multi-threaded environments like Django views and middleware.
Complex Dictionary Format¶
For COUNTRIES_ONLY and COUNTRIES_OVERRIDE, you can also provide a dictionary rather than just a translatable string for the country name.
The options within the dictionary are:
name or names (required)¶
Either a single translatable name for this country or a list of multiple translatable names. If using multiple names, the first name takes preference when using COUNTRIES_FIRST or the Country.name.
COUNTRIES_OVERRIDE = {
"US": {
"names": [
_("United States of America"),
_("USA"),
_("America"),
],
},
}
alpha3 (optional)¶
An ISO 3166-1 three character code (or an empty string to nullify an existing code for this country):
numeric (optional)¶
An ISO 3166-1 numeric country code (or None to nullify an existing code for this country). The numeric codes 900 to 999 are left available by the standard for user-assignment:
ioc_code (optional)¶
The country's International Olympic Committee code (or an empty string to nullify an existing code):
flag_url (optional)¶
New in version 8.2.0
Per-country flag_url overrides allow custom country codes to reuse existing flag image assets or point to bespoke flags.
A custom flag image URL for this country. This is particularly useful when using custom country codes that need to reference existing flag images:
COUNTRIES_OVERRIDE = {
"ID": None, # Remove Indonesia
"IND": {
"names": [_("Indonesia")],
"ioc_code": "INA",
"flag_url": "flags/id.gif", # Points to id.gif instead of ind.gif
},
}
The flag URL supports the same placeholders as COUNTRIES_FLAG_URL:
{code}- lowercase country code{code_upper}- uppercase country code
Tip
When specifying only metadata fields (like flag_url, ioc_code) without providing name or names, the original country name is preserved. This allows you to customize flags or codes without losing the standard country name:
Complete Example¶
from django.utils.translation import gettext_lazy as _
COUNTRIES_OVERRIDE = {
"NZ": {
"names": [_("New Zealand"), _("Aotearoa")],
"alpha3": "NZL",
"numeric": 554,
"ioc_code": "NZL",
},
"XX": {
"names": [_("Custom Country")],
"alpha3": "XXX",
"numeric": 900,
"ioc_code": "",
"flag_url": "flags/custom/{code}.png",
},
}
Country Object External Plugins¶
Other Python packages can add attributes to the Country object by using entry points in their setup script.
For example, you could create a django_countries_phone package with the following entry point in the setup.py or pyproject.toml file. The entry point name (phone) will be the new attribute name on the Country object. The attribute value will be the return value of the get_phone function (called with the Country instance as the sole argument).
setup.py Example¶
setup(
...
entry_points={
"django_countries.Country": "phone = django_countries_phone.get_phone"
},
...
)
pyproject.toml Example¶
Then in your code:
>>> from django_countries import countries
>>> country = countries['US']
>>> country.phone # Calls get_phone(country)
'+1'
See Also¶
- Dynamic Ordering - Language-based and automatic country ordering
- Settings Reference - Complete list of all settings
- ISO 3166-1 Formatting - Understanding official country name conventions
- CountryField Reference - Learn about the country field
- Multiple Countries - Handle multiple country selection