26. Country Select Field with Flag Symbol

In many applications we need an input field to select one or more countries. To give a visually better feedback, adding the flag symbol nearby the country’s name is often a good idea.

Since django-formset does not know anything about the countries of this world, we first shall install the package django-countries. This package provides the Django model field django_countries.fields.CountryField and is rendered as a select field with all countries. The field is based on the Django field django.db.models.CharField and stores the country code in the database. The country code is a two letter code, e.g. DE for Germany or US for the United States, etc.

pip install django-countries

Strictly speaking, we do not need the package django-countries if we know the country codes and names, and if we can provide them as a list of tuples. But the package django-countries is useful, since it provides this list with all existing country names translated into more than 36 languages.

We also need to install a package providing the flag icons. This can be found in NodeJS:

npm install flag-icons

Since we want to serve the flag icons directly from the node_modules directory, we need to configure our Django setting.py as follows:

STATICFILES_DIRS = [
    ...
    ('node_modules', BASE_DIR / 'node_modules'),
    ...
]

26.1. Select a single Country

Whenever we need an input field to select a single country, django-formset offers the special widget formset.widgets.CountrySelectize. This can be used as a direct replacement for the built-in widget django.forms.widgets.Select and shall be used with the Django form field django.forms.fields.ChoiceField.

Here as an example, we create a simple address form with just a single field named country. This field is rendered as a select field showing all countries prefixed by their flags.

form.py
from django.forms import fields, forms
from django_countries import countries
from formset.widgets import CountrySelectize

class AddressForm(forms.Form):
    country = fields.ChoiceField(
        widget=CountrySelectize,
        choices=countries,
    )

Here for instance, we only use the list of countries provided by the package django-countries.

As the controlling Django view, we can use a class inheriting from formset.views.FormView, as we did in all the other examples.

26.2. Select multiple Countries

Whenever we need an input field to select multiple countries, django-formset offers the special widget formset.widgets.CountrySelectizeMultiple. This can be used as a direct replacement built-in widget django.forms.widgets.SelectMultiple and shall be used with the Django form field django.forms.fields.MultipleChoiceField.

Here as an example, we create a simple visitor form with just a single field named from_countries. This field is rendered as a multiple select field showing all countries prefixed by their flags.

form.py
from django.forms import fields, forms
from django_countries import countries
from formset.widgets import CountrySelectizeMultiple

class VisitorsForm(forms.Form):
    countries = fields.MultipleChoiceField(
        label="From Countries",
        widget=CountrySelectizeMultiple(max_items=15),
        choices=countries,
        help_text="Select up to 15 countries",
    )

Here for instance, we only use the list of countries provided by the package django-countries.

As the controlling Django view, we can use a class inheriting from formset.views.FormView, as we did in all the other examples.

Select up to 15 countries

26.3. Implementation Details

Both widgets formset.widgets.CountrySelectize and formset.widgets.CountrySelectizeMultiple are based on the widgets formset.widgets.Selectize and formset.widgets.SelectizeMultiple respectively. The only difference is that the selectable options prepend the flag symbol to their country name. This is possible because the underlying JavaScript library TomSelect.js allows to customize nearly every aspect of HTML.