django-countries
A Django model and form field for ISO 3166-1 country choices, with translated names and flag icons built in.
Repository Health
Technical Analysis
django-countries is a Django application that adds a CountryField for models and forms, backed by the full ISO 3166-1 country list. Rather than hand-rolling a CharField with a giant choices= tuple, it gives you a drop-in field whose values behave like rich Country objects — comparable to plain codes, but carrying a translated display name and a static flag icon URL for free.
Beyond the core field, the package covers the integrations a real project needs around country data: Django REST Framework serializer fields, GraphQL types for graphene-django, django-filter support for queryset filtering, multi-select country fields, and pluggable custom country lists via setuptools entry points. Country names are translated through Django’s standard gettext machinery, sourced from an actively maintained Transifex project.
What You Get
- A
CountryFieldfor Django models storing the ISO alpha-2 code with full form/admin integration - Rich
Countryobjects with translated names, alpha-3/numeric/IOC codes, and flag URLs - Static flag icon assets for every ISO 3166-1 country, served through Django’s static files
- Django REST Framework serializer fields and graphene-django GraphQL type support
- django-filter integration for filtering querysets by country
- Support for multi-select country fields and custom/extended country lists via entry points
Common Use Cases
- Adding a country selector to a user profile or address model without hand-maintaining a choices list
- Rendering a translated country name and flag in templates for an internationalized site
- Exposing country fields through a DRF API or GraphQL schema in a consistent, typed way
- Filtering an admin changelist or queryset by country using django-filter
- Building shipping/billing forms that need ISO-compliant country codes for downstream integrations
Under The Hood
Architecture
The package centers on fields.py, where CountryField subclasses Django’s CharField and overrides value conversion so reads/writes pass through the Country wrapper defined in __init__.py; Countries/countries (in base.py and __init__.py) own the ISO dataset in data.py and expose lookups by alpha-2/alpha-3/numeric/IOC code, with conf.py bridging Django settings for overrides. Peripheral concerns are cleanly separated into their own modules: widgets.py for the form widget and flag-changing JS hook, serializers.py/serializer_fields.py for DRF, a graphql/ subpackage for graphene-django types, and django_filters.py/filters.py for queryset filtering — each is optional and only imported if the consuming project uses that integration, so the core field has no hard dependency on DRF or GraphQL being installed.
Tech Stack
The library targets modern Django (4.2 LTS through 6.0) and Python 3.10-3.14, declaring only asgiref and typing_extensions as hard runtime dependencies, with pyuca as an optional extra for locale-aware sorting. It builds with uv_build rather than setuptools, and its dev/test tooling (declared in pyproject.toml dependency groups) spans pytest/pytest-django/pytest-cov, ruff, mypy with django-stubs, bandit, and towncrier for changelog management, orchestrated through a justfile rather than raw tox or make.
Code Quality
The django_countries/tests/ directory holds a comprehensive suite covering fields, admin display, admin filters, DRF serialization, GraphQL, widgets, template tags, settings, and null-handling, run across a CI matrix of legacy/previous/latest Python-Django combinations plus pyuca and no-i18n variants. The package ships a py.typed marker and a hand-written fields.pyi stub alongside mypy configured with disallow_untyped_calls and the Django mypy plugin, giving it a stricter type-checking posture than most Django add-ons; a dedicated lint-and-type-check CI job runs ruff and mypy on every push.
API Design
CountryField is designed to be a near drop-in replacement for a plain CharField/choices setup, so existing model code migrates with minimal changes, while the returned Country objects layer in __eq__/__str__/__bool__ so they compare and render naturally against plain string codes without extra unwrapping. Extensibility is opt-in via setuptools entry points (django_countries.Country) rather than subclassing requirements, and optional integrations (DRF, GraphQL, django-filter) are additive modules a project only touches if it needs them, keeping the base API surface small.
Used by 2 apps in this directory
authentik
Authentication · Security
The self-hosted Identity Provider that replaces Okta, Auth0, and Entra ID with a unified SSO platform supporting SAML, OAuth2/OIDC, LDAP, RADIUS, and WebAuthn.
Docs
File Storage · CMS
Open-source collaborative knowledge platform with real-time editing, AI writing tools, and full self-hosting control — built by the French and German governments.