CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-countries

A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

Pending
Overview
Eval results
Files

form-fields-widgets.mddocs/

Form Fields and Widgets

Specialized Django form fields and widgets for country selection with lazy-loaded choices, flag display support, and JavaScript integration. These components provide enhanced user interfaces for country selection in Django forms.

Capabilities

Form Fields

Django form fields that provide country selection with lazy-loaded choices and proper validation.

class LazyTypedChoiceField(forms.TypedChoiceField):
    """
    Form field for single country selection with lazy-loaded country choices.
    """
    choices: Any
    widget: LazySelect

class LazyTypedMultipleChoiceField(forms.TypedMultipleChoiceField):
    """
    Form field for multiple country selection with lazy-loaded country choices.
    """
    choices: Any  
    widget: LazySelectMultiple

Widgets

Django form widgets with enhanced country selection interfaces and flag display capabilities.

class LazySelect(widgets.Select):
    """
    Select widget with lazy-loaded country choices.
    """
    def __init__(self, attrs=None, choices=()):
        """
        Initialize select widget with lazy choice loading.
        
        Parameters:
        - attrs: dict - HTML attributes for widget
        - choices: iterable - Choice options (loaded lazily)
        """

class LazySelectMultiple(widgets.SelectMultiple):
    """
    Multiple select widget with lazy-loaded country choices.
    """
    def __init__(self, attrs=None, choices=()):
        """
        Initialize multiple select widget with lazy choice loading.
        
        Parameters:
        - attrs: dict - HTML attributes for widget  
        - choices: iterable - Choice options (loaded lazily)
        """

class CountrySelectWidget(LazySelect):
    """
    Enhanced country select widget with flag display and JavaScript integration.
    """
    def __init__(
        self,
        layout=None,
        attrs=None, 
        choices=(),
        flag_url=None
    ):
        """
        Initialize country select widget with flag support.
        
        Parameters:
        - layout: str - Widget layout template
        - attrs: dict - HTML attributes for widget
        - choices: iterable - Country choices
        - flag_url: str - Flag image URL pattern
        """

Usage Examples

Basic Form Usage

from django import forms
from django_countries.fields import LazyTypedChoiceField, LazyTypedMultipleChoiceField
from django_countries import countries

class PersonForm(forms.Form):
    # Single country selection
    country = LazyTypedChoiceField(choices=countries)
    
    # Multiple country selection
    visited_countries = LazyTypedMultipleChoiceField(
        choices=countries,
        required=False
    )

class EventForm(forms.Form):
    # With custom widget attributes
    country = LazyTypedChoiceField(
        choices=countries,
        widget=forms.Select(attrs={
            'class': 'form-control',
            'data-placeholder': 'Select country'
        })
    )

Model Form Integration

from django import forms
from django_countries.widgets import CountrySelectWidget
from myapp.models import Organization

class OrganizationForm(forms.ModelForm):
    class Meta:
        model = Organization
        fields = ['name', 'country', 'operating_countries']
        widgets = {
            'country': CountrySelectWidget(attrs={
                'class': 'country-select'
            }),
            'operating_countries': forms.SelectMultiple(attrs={
                'class': 'multi-country-select'
            })
        }

Custom Widget Configuration

from django_countries.widgets import CountrySelectWidget

class CustomCountryForm(forms.Form):
    country = forms.CharField(
        widget=CountrySelectWidget(
            flag_url="custom/flags/{code}.png",
            attrs={
                'class': 'custom-country-widget',
                'onchange': 'updateFlag(this.value)'
            }
        )
    )

Widget Features

Flag Display Integration

The CountrySelectWidget includes JavaScript for dynamic flag display:

from django_countries.widgets import CountrySelectWidget

# Widget with flag support
widget = CountrySelectWidget(
    flag_url="flags/{code_upper}.png",
    attrs={'id': 'country_select'}
)

# Generated JavaScript automatically updates flag images
# with ID pattern: 'flag_' + widget_id

HTML template example:

<form>
    {{ form.country }}
    <img id="flag_country_select" src="flags/__.png" alt="Flag">
</form>

Lazy Choice Loading

Widgets support lazy choice loading to avoid loading country data until needed:

from django_countries.widgets import LazySelect
from django_countries import countries

# Choices loaded only when widget is rendered
widget = LazySelect(choices=countries)

# Works with filtered countries too
filtered_countries = Countries()
filtered_countries.only = ["US", "CA", "MX"]
widget = LazySelect(choices=filtered_countries)

Custom Choice Lists

from django_countries import Countries

# Create custom countries instance
asia_countries = Countries()
asia_countries.only = ["CN", "JP", "KR", "IN", "TH", "VN"]

class AsiaEventForm(forms.Form):
    country = LazyTypedChoiceField(
        choices=asia_countries,
        widget=CountrySelectWidget()
    )

Widget Mixins

LazyChoicesMixin

Mixin providing lazy choice loading functionality for Django < 5.0 compatibility:

class LazyChoicesMixin:
    """Mixin for widgets that support lazy-loaded choices."""
    
    def get_choices(self) -> List[List[Union[int, str]]]:
        """Get choices, evaluating lazy choices if needed."""
    
    def set_choices(self, value):
        """Set widget choices."""
    
    choices = property(get_choices, set_choices)

LazySelectMixin

Combined mixin for select widgets with lazy choices:

class LazySelectMixin(LazyChoicesMixin):
    """Mixin combining lazy choices with select widget functionality."""
    
    def __deepcopy__(self, memo):
        """Deep copy widget with choices preservation."""

Advanced Widget Customization

Custom Flag URL Patterns

Configure different flag image patterns:

# Different flag formats
widget1 = CountrySelectWidget(flag_url="flags/4x3/{code}.svg")
widget2 = CountrySelectWidget(flag_url="https://flags.api.com/{code_upper}.png")
widget3 = CountrySelectWidget(flag_url="assets/country-flags/{code}-flag.gif")

Available template variables:

  • {code}: lowercase country code (e.g., "us")
  • {code_upper}: uppercase country code (e.g., "US")

JavaScript Integration

The widget automatically generates JavaScript for flag updates:

// Auto-generated JavaScript pattern
var e=document.getElementById('flag_' + this.id); 
if (e) e.src = 'flags/{code}.gif'
    .replace('{code}', this.value.toLowerCase() || '__')
    .replace('{code_upper}', this.value.toUpperCase() || '__');

Custom Widget Templates

For advanced customization, create custom widget templates:

class CustomCountryWidget(CountrySelectWidget):
    template_name = 'custom_widgets/country_select.html'
    
    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        context['flag_url_pattern'] = self.flag_url
        return context

Form Integration Patterns

With Django Crispy Forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field

class CountryForm(forms.Form):
    country = LazyTypedChoiceField(choices=countries)
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
            Field('country', css_class='country-select')
        )

Custom Validation

class StrictCountryForm(forms.Form):
    country = LazyTypedChoiceField(choices=countries)
    
    def clean_country(self):
        country = self.cleaned_data['country']
        if not country:
            raise forms.ValidationError("Country is required")
        
        # Additional validation
        if country not in ["US", "CA", "MX"]:
            raise forms.ValidationError("Only North American countries allowed")
        
        return country

Dynamic Widget Configuration

class DynamicCountryForm(forms.Form):
    def __init__(self, *args, region=None, **kwargs):
        super().__init__(*args, **kwargs)
        
        if region == 'europe':
            eu_countries = Countries()
            eu_countries.only = ["DE", "FR", "IT", "ES", "NL", "BE"]
            self.fields['country'] = LazyTypedChoiceField(choices=eu_countries)
        else:
            self.fields['country'] = LazyTypedChoiceField(choices=countries)

Install with Tessl CLI

npx tessl i tessl/pypi-django-countries

docs

admin-integration.md

countries-registry.md

django-rest-framework.md

form-fields-widgets.md

graphql-support.md

index.md

model-fields.md

template-tags.md

tile.json