# django-countries for Django country fields and flags

> django-countries adds ISO 3166-1 country choices, a model field, translated names, flag assets, and API integrations to Django. It fits applications that store one or multiple countries, although customization details and upgrade policy remain concentrated in the external documentation.

**SmileyChris/django-countries** — A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

- Repository: https://github.com/SmileyChris/django-countries
- Website: http://smileychris.github.io/django-countries/
- Stars: 1,529 · Forks: 301
- Language: Python
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/smileychris-django-countries

## Why django-countries fits country-aware Django models

django-countries addresses a narrow but recurring Django problem: applications need country values in forms and database records, plus display assets for those values. The package describes itself as a country field for models and lists ISO 3166-1 countries. That makes it relevant to profiles, addresses, shipping rules, localization settings, or any form whose choices must be represented consistently. The repository is aimed at Python and Django developers rather than users of a standalone country database.

The package reduces several related tasks to one Django application. It supplies country choices, a `CountryField`, translated country names through Django's i18n system, and static flag image files. The README also states that it integrates with Django REST Framework and graphene-django and supports selecting multiple countries. Those features matter because a country value can appear in database, HTML form, administrative, and API contexts without each layer inventing a separate representation.

The feature set still reflects an ISO 3166-1 country model. The README does not discuss subdivisions, currencies, dialing codes, nationalities, or other country metadata. A project that needs more than country identifiers should not assume those adjacent datasets are included. The visible scope is country selection and presentation, with translated names and flags as its main additions to Django's field machinery.

## How CountryField moves country data through Django

The first documented data path begins with a normal Django model field. Application code imports `CountryField`, places it on a model, and stores the country as part of that model. Because the package is added to `INSTALLED_APPS`, Django can load the application as part of the project configuration rather than treating country choices as an unrelated template-only helper.

Presentation is handled through Django's existing systems. Country names are translated with `gettext`, which means the package participates in the framework's translation machinery rather than shipping a separate localization API. Forms receive country choices from the application, while the flag feature provides static image files that templates and front-end code can request through Django's static-file handling.

The README also records integrations for Django REST Framework and graphene-django. Those claims indicate that country fields can participate in common Django API stacks, but the repository excerpt does not provide serializer schemas, GraphQL types, or configuration steps. It would be unsafe to infer exact payload formats from the feature names alone. Those details must be confirmed in the linked full documentation before an API contract is designed.

Multiple-country support broadens the model path beyond a single value. The overview states that the package supports multiple selection, but it does not show the field declaration or storage type in the README excerpt. As a result, the exact database representation, serialization format, and validation behavior cannot be established from the repository files.

## Installing django-countries and defining the first model

The README documents a direct pip installation. Install the package in the same Python environment used by the Django project:

```bash
pip install django-countries
```

After installation, register `django_countries` in the Django settings. The documented entry is an application name, not a dotted import path:

```python
INSTALLED_APPS = [
    # ...
    'django_countries',
]
```

A first model can then use the package's field exactly as shown in the README:

```python
from django_countries.fields import CountryField

class Person(models.Model):
    country = CountryField()
```

This is only a model declaration. The README does not show the corresponding `makemigrations` or `migrate` commands, so those steps are intentionally omitted here. It also does not document required settings for flag output or detailed form rendering. Those are implementation checks for the project's full documentation, not steps that can be safely reconstructed from the repository summary.

The package requires Python 3.10 or newer. The declared Django support covers 4.2, 5.2, 6.0, and 6.1, while Django REST Framework integration is listed for version 3.14 and newer. The project metadata also includes `asgiref` and `typing_extensions` as runtime dependencies, while `pyuca` is optional.

## Flags, translations, forms, and API boundaries

Flag icons are static files rather than a rendering framework. The repository feature list says that images are included for all countries, which gives templates a conventional Django static asset path after installation. The README excerpt does not identify that path, file naming scheme, size options, or fallback behavior. It therefore cannot support a precise template example without risking an incorrect asset URL.

Translated names are a more integrated feature. The package draws country labels from Django's standard `gettext` mechanism, with translations managed through a Transifex project. This is attractive for applications that already localize form labels and model choices. It also means translation completeness belongs to a separate localization pipeline. The repository files do not enumerate locales or state how fallback labels behave, so those specifics remain a documentation question.

Forms, REST Framework, and GraphQL all sit on top of the same country data concept. That reduces the number of separate country implementations in a typical application, but it does not make their interfaces identical. A form choice representation, a REST serializer output, and a GraphQL enum or field can expose different shapes. The README confirms integration support without defining those shapes. Teams with existing API contracts should verify the generated or documented output before adopting it.

The optional `pyuca` dependency is also significant. The repository exposes it as an optional package, but the README does not explain when it is selected or how it changes country resolution. It should not be installed merely because it is available.

## Compatibility limits and the cost of adopting CountryField

Compatibility is broader than the basic installation example suggests, but it is explicitly versioned. Python support runs from 3.10 through 3.14. Django support includes the two LTS lines identified in the metadata, 4.2 and 5.2, plus 6.0 and 6.1. Django REST Framework 3.14+ is supported for its integration. A project running another Python or Django version has no compatibility guarantee in the README.

The metadata labels version 9.1.0 as `Development Status :: 5 - Production/Stable`. That is a package classification, not independent evidence about a particular application. It does, however, accompany an explicit compatibility matrix. The repository is not archived, and its last push was on 2026-09-10, although the repository has no GitHub releases. Changes are therefore recorded through repository history and `CHANGES.md`, not a stated GitHub release cadence.

Database adoption carries an upgrade cost that depends on the existing schema. The README does not state the field's column type, maximum length, migration behavior, or compatibility with data that already stores two-letter country codes. Changing a model field is not equivalent to installing a stateless template helper. Projects should compare the documented storage format with their current tables before replacing a `CharField` or another representation.

The MIT license permits reuse and modification under its terms, including for commercial and closed-source distributions. It does not grant trademark rights or eliminate the obligation to preserve applicable license notices. The repository does not describe any separate paid service, hosted component, or runtime license.

## When a standard Django choice field is the better alternative

The practical alternative is a project-owned Django choice field backed by a fixed list of ISO 3166-1 codes. This approach uses Django's ordinary model and form mechanisms directly, while the application owns the choice labels, validation, ordering, translations, and any flags. It involves less dependency-specific configuration, but it also makes the application responsible for keeping that data consistent and usable across interfaces.

This may be the better fit when an application already has an approved country vocabulary, needs unusual labels or ordering, or has a database schema whose country representation cannot change. django-countries is more relevant when the application wants the package to supply the field, the country set, translated names, static flags, and recognized framework integrations. Its documented feature set can save duplicated code, but that convenience creates a dependency on the package's data model and supported version matrix.

The two approaches differ in ownership rather than in the basic idea of validating country choices. django-countries centralizes common country behavior in a reusable Django application. The standard choice-field approach keeps everything in the project and may be easier to tailor, while increasing the number of details the project must maintain. The repository does not compare django-countries with another package, so neither option should be described as having faster queries or better validation.

## Conclusion

Adopt django-countries when a Django application needs ISO 3166-1 country storage without maintaining its own country list, translation layer, and flag assets. Do not choose it merely to customize country policy, because the repository overview does not explain the available extension points or whether its database representation fits an existing schema. Verify Python and Django compatibility first, then check the external documentation for migrations, validation behavior, flag configuration, and API-specific setup before changing a production model.

## FAQ

### How do I install django-countries in a Django project?

Install it with `pip install django-countries`, then add `'django_countries'` to the Django `INSTALLED_APPS` list.

### Which Python and Django versions does django-countries support?

The project supports Python 3.10 through 3.14 and Django 4.2, 5.2, 6.0, and 6.1. Django REST Framework integration is listed for version 3.14 and newer.

### Can django-countries store and select multiple countries?

Yes. The README lists multiple country selection as a feature, although it does not show the field declaration or its database representation.

## Sources

- [Issues](https://github.com/SmileyChris/django-countries/issues)
- [License: MIT](https://github.com/SmileyChris/django-countries/blob/main/LICENSE)
- [Project website](http://smileychris.github.io/django-countries/)
- [README](https://github.com/SmileyChris/django-countries/blob/main/README.md)
- [SmileyChris/django-countries on GitHub](https://github.com/SmileyChris/django-countries)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/smileychris-django-countries
