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

django-rest-framework.mddocs/

Django REST Framework Integration

Serializer fields and mixins for Django REST Framework providing country serialization with flexible output formats. The integration supports code-only, name-only, and dictionary representations with automatic model field mapping.

Capabilities

CountryField Serializer

Specialized DRF serializer field for country data with flexible output formatting options.

class CountryField(serializers.ChoiceField):
    def __init__(
        self,
        *args,
        country_dict=None,
        name_only=None,
        countries=None,
        **kwargs
    ):
        """
        DRF serializer field for country representation.
        
        Parameters:
        - country_dict: bool - Return country as {'code': 'US', 'name': 'United States'}
        - name_only: bool - Return only country name instead of code
        - countries: Countries - Custom countries instance
        - **kwargs: Standard ChoiceField arguments
        """

    def to_representation(self, obj):
        """
        Convert country code to serialized representation.
        
        Parameters:
        - obj: Country code or Country object
        
        Returns:
        - Serialized country data based on field configuration
        """

    def to_internal_value(self, data):
        """
        Convert serialized data to country code.
        
        Parameters:
        - data: Serialized country data (code, name, or dict)
        
        Returns:
        - str: Country code for internal storage
        """

Model Serializer Mixin

Automatic field mapping mixin for ModelSerializer classes that converts CountryField model fields to appropriate serializer fields.

class CountryFieldMixin:
    def build_standard_field(self, field_name, model_field):
        """
        Build appropriate serializer field for CountryField model fields.
        
        Parameters:
        - field_name: str - Name of the field
        - model_field: CountryField - Model field instance
        
        Returns:
        - Tuple[Field, dict]: Serializer field class and kwargs
        """

Usage Examples

Basic Serializer Usage

from rest_framework import serializers
from django_countries.serializer_fields import CountryField

class PersonSerializer(serializers.Serializer):
    name = serializers.CharField()
    
    # Return country code only (default)
    country = CountryField()
    
    # Return country name only
    birth_country = CountryField(name_only=True)
    
    # Return country as dictionary with code and name
    residence = CountryField(country_dict=True)

# Sample output:
# {
#     "name": "John Doe",
#     "country": "US", 
#     "birth_country": "United States",
#     "residence": {"code": "US", "name": "United States"}
# }

Model Serializer Integration

from rest_framework import serializers
from django_countries.serializers import CountryFieldMixin
from myapp.models import Person

class PersonModelSerializer(CountryFieldMixin, serializers.ModelSerializer):
    """
    ModelSerializer with automatic CountryField mapping.
    CountryFieldMixin automatically converts model CountryFields to serializer CountryFields.
    """
    class Meta:
        model = Person
        fields = ['name', 'country', 'visited_countries']

# Alternative manual configuration
class PersonCustomSerializer(serializers.ModelSerializer):
    country = CountryField(country_dict=True)
    visited_countries = serializers.ListField(
        child=CountryField(name_only=True)
    )
    
    class Meta:
        model = Person
        fields = ['name', 'country', 'visited_countries']

Custom Countries Instance

from django_countries import Countries
from django_countries.serializer_fields import CountryField

# Create custom countries list
eu_countries = Countries()
eu_countries.only = ["DE", "FR", "IT", "ES", "NL", "BE"]

class EuropeanEventSerializer(serializers.Serializer):
    title = serializers.CharField()
    country = CountryField(countries=eu_countries)

Input/Output Formats

Input Format Handling

The CountryField accepts multiple input formats:

# Valid input formats for CountryField:

# 1. Country code (alpha2, alpha3, numeric)
{"country": "US"}
{"country": "USA"} 
{"country": "840"}

# 2. Country name (exact match)
{"country": "United States"}

# 3. Dictionary format
{"country": {"code": "US"}}
{"country": {"code": "US", "name": "United States"}}

Output Format Options

class FlexiblePersonSerializer(serializers.Serializer):
    name = serializers.CharField()
    
    # Code only (default): "US"
    country_code = CountryField()
    
    # Name only: "United States" 
    country_name = CountryField(name_only=True)
    
    # Dictionary: {"code": "US", "name": "United States"}
    country_full = CountryField(country_dict=True)

Multiple Countries Handling

from rest_framework import serializers
from django_countries.serializer_fields import CountryField

class OrganizationSerializer(serializers.ModelSerializer):
    # Multiple countries as list of codes
    operating_countries = serializers.ListField(
        child=CountryField()
    )
    
    # Multiple countries as list of names
    operating_regions = serializers.ListField(
        child=CountryField(name_only=True)
    )
    
    # Multiple countries as list of dictionaries
    detailed_countries = serializers.ListField(
        child=CountryField(country_dict=True)
    )

# Sample output:
# {
#     "operating_countries": ["US", "CA", "MX"],
#     "operating_regions": ["United States", "Canada", "Mexico"],
#     "detailed_countries": [
#         {"code": "US", "name": "United States"},
#         {"code": "CA", "name": "Canada"}, 
#         {"code": "MX", "name": "Mexico"}
#     ]
# }

Advanced Usage

Validation and Error Handling

class StrictCountrySerializer(serializers.Serializer):
    country = CountryField()
    
    def validate_country(self, value):
        """Custom country validation."""
        if value not in ["US", "CA", "MX"]:
            raise serializers.ValidationError(
                "Only North American countries are allowed"
            )
        return value

# Invalid country codes raise ValidationError:
# serializer = StrictCountrySerializer(data={"country": "INVALID"})
# serializer.is_valid()  # False
# serializer.errors  # {"country": ["Select a valid choice..."]}

ViewSet Integration

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

class PersonViewSet(viewsets.ModelViewSet):
    serializer_class = PersonModelSerializer
    
    @action(detail=False, methods=['get'])
    def countries(self, request):
        """Return list of all available countries."""
        from django_countries import countries
        
        country_list = [
            {"code": country.code, "name": country.name} 
            for country in countries
        ]
        return Response(country_list)
    
    @action(detail=False, methods=['get'])
    def by_country(self, request):
        """Filter people by country."""
        country_code = request.query_params.get('country')
        if country_code:
            queryset = self.get_queryset().filter(country=country_code)
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
        return Response([])

Custom Field Behavior

class ExtendedCountryField(CountryField):
    """Custom country field with additional metadata."""
    
    def to_representation(self, obj):
        """Add additional country metadata."""
        from django_countries import countries
        
        code = countries.alpha2(obj)
        if not code:
            return ""
            
        return {
            "code": code,
            "name": countries.name(code),
            "alpha3": countries.alpha3(code),
            "numeric": countries.numeric(code),
            "flag_url": f"/static/flags/{code.lower()}.gif"
        }

class DetailedPersonSerializer(serializers.Serializer):
    name = serializers.CharField()
    country = ExtendedCountryField()

# Output:
# {
#     "name": "John Doe",
#     "country": {
#         "code": "US",
#         "name": "United States", 
#         "alpha3": "USA",
#         "numeric": 840,
#         "flag_url": "/static/flags/us.gif"
#     }
# }

Filtering and Search

from django_filter import rest_framework as filters

class PersonFilter(filters.FilterSet):
    country = filters.CharFilter(field_name='country')
    country_name = filters.CharFilter(
        field_name='country',
        lookup_expr='name_icontains'
    )
    
    class Meta:
        model = Person
        fields = ['country', 'country_name']

class PersonViewSet(viewsets.ModelViewSet):
    serializer_class = PersonModelSerializer
    filterset_class = PersonFilter
    
    # URL examples:
    # /api/people/?country=US
    # /api/people/?country_name=united

Integration Patterns

API Versioning

class PersonV1Serializer(serializers.ModelSerializer):
    """v1 API returns country codes only."""
    country = CountryField()
    
    class Meta:
        model = Person
        fields = ['name', 'country']

class PersonV2Serializer(serializers.ModelSerializer): 
    """v2 API returns country with full details."""
    country = CountryField(country_dict=True)
    
    class Meta:
        model = Person
        fields = ['name', 'country']

Nested Serialization

class AddressSerializer(serializers.Serializer):
    street = serializers.CharField()
    city = serializers.CharField()
    country = CountryField(country_dict=True)

class PersonWithAddressSerializer(serializers.Serializer):
    name = serializers.CharField()
    address = AddressSerializer()

# Output:
# {
#     "name": "John Doe",
#     "address": {
#         "street": "123 Main St",
#         "city": "New York", 
#         "country": {"code": "US", "name": "United States"}
#     }
# }

Performance Optimization

class OptimizedPersonSerializer(serializers.ModelSerializer):
    """Optimized serializer for bulk operations."""
    
    # Use code-only for better performance in lists
    country = CountryField()
    
    def to_representation(self, instance):
        """Add country name only when needed."""
        data = super().to_representation(instance)
        
        # Add country name for detail views
        if self.context.get('detail_view'):
            from django_countries import countries
            data['country_name'] = countries.name(data['country'])
            
        return data

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