0
# Django REST Framework Integration
1
2
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.
3
4
## Capabilities
5
6
### CountryField Serializer
7
8
Specialized DRF serializer field for country data with flexible output formatting options.
9
10
```python { .api }
11
class CountryField(serializers.ChoiceField):
12
def __init__(
13
self,
14
*args,
15
country_dict=None,
16
name_only=None,
17
countries=None,
18
**kwargs
19
):
20
"""
21
DRF serializer field for country representation.
22
23
Parameters:
24
- country_dict: bool - Return country as {'code': 'US', 'name': 'United States'}
25
- name_only: bool - Return only country name instead of code
26
- countries: Countries - Custom countries instance
27
- **kwargs: Standard ChoiceField arguments
28
"""
29
30
def to_representation(self, obj):
31
"""
32
Convert country code to serialized representation.
33
34
Parameters:
35
- obj: Country code or Country object
36
37
Returns:
38
- Serialized country data based on field configuration
39
"""
40
41
def to_internal_value(self, data):
42
"""
43
Convert serialized data to country code.
44
45
Parameters:
46
- data: Serialized country data (code, name, or dict)
47
48
Returns:
49
- str: Country code for internal storage
50
"""
51
```
52
53
### Model Serializer Mixin
54
55
Automatic field mapping mixin for ModelSerializer classes that converts CountryField model fields to appropriate serializer fields.
56
57
```python { .api }
58
class CountryFieldMixin:
59
def build_standard_field(self, field_name, model_field):
60
"""
61
Build appropriate serializer field for CountryField model fields.
62
63
Parameters:
64
- field_name: str - Name of the field
65
- model_field: CountryField - Model field instance
66
67
Returns:
68
- Tuple[Field, dict]: Serializer field class and kwargs
69
"""
70
```
71
72
## Usage Examples
73
74
### Basic Serializer Usage
75
76
```python
77
from rest_framework import serializers
78
from django_countries.serializer_fields import CountryField
79
80
class PersonSerializer(serializers.Serializer):
81
name = serializers.CharField()
82
83
# Return country code only (default)
84
country = CountryField()
85
86
# Return country name only
87
birth_country = CountryField(name_only=True)
88
89
# Return country as dictionary with code and name
90
residence = CountryField(country_dict=True)
91
92
# Sample output:
93
# {
94
# "name": "John Doe",
95
# "country": "US",
96
# "birth_country": "United States",
97
# "residence": {"code": "US", "name": "United States"}
98
# }
99
```
100
101
### Model Serializer Integration
102
103
```python
104
from rest_framework import serializers
105
from django_countries.serializers import CountryFieldMixin
106
from myapp.models import Person
107
108
class PersonModelSerializer(CountryFieldMixin, serializers.ModelSerializer):
109
"""
110
ModelSerializer with automatic CountryField mapping.
111
CountryFieldMixin automatically converts model CountryFields to serializer CountryFields.
112
"""
113
class Meta:
114
model = Person
115
fields = ['name', 'country', 'visited_countries']
116
117
# Alternative manual configuration
118
class PersonCustomSerializer(serializers.ModelSerializer):
119
country = CountryField(country_dict=True)
120
visited_countries = serializers.ListField(
121
child=CountryField(name_only=True)
122
)
123
124
class Meta:
125
model = Person
126
fields = ['name', 'country', 'visited_countries']
127
```
128
129
### Custom Countries Instance
130
131
```python
132
from django_countries import Countries
133
from django_countries.serializer_fields import CountryField
134
135
# Create custom countries list
136
eu_countries = Countries()
137
eu_countries.only = ["DE", "FR", "IT", "ES", "NL", "BE"]
138
139
class EuropeanEventSerializer(serializers.Serializer):
140
title = serializers.CharField()
141
country = CountryField(countries=eu_countries)
142
```
143
144
## Input/Output Formats
145
146
### Input Format Handling
147
148
The CountryField accepts multiple input formats:
149
150
```python
151
# Valid input formats for CountryField:
152
153
# 1. Country code (alpha2, alpha3, numeric)
154
{"country": "US"}
155
{"country": "USA"}
156
{"country": "840"}
157
158
# 2. Country name (exact match)
159
{"country": "United States"}
160
161
# 3. Dictionary format
162
{"country": {"code": "US"}}
163
{"country": {"code": "US", "name": "United States"}}
164
```
165
166
### Output Format Options
167
168
```python
169
class FlexiblePersonSerializer(serializers.Serializer):
170
name = serializers.CharField()
171
172
# Code only (default): "US"
173
country_code = CountryField()
174
175
# Name only: "United States"
176
country_name = CountryField(name_only=True)
177
178
# Dictionary: {"code": "US", "name": "United States"}
179
country_full = CountryField(country_dict=True)
180
```
181
182
### Multiple Countries Handling
183
184
```python
185
from rest_framework import serializers
186
from django_countries.serializer_fields import CountryField
187
188
class OrganizationSerializer(serializers.ModelSerializer):
189
# Multiple countries as list of codes
190
operating_countries = serializers.ListField(
191
child=CountryField()
192
)
193
194
# Multiple countries as list of names
195
operating_regions = serializers.ListField(
196
child=CountryField(name_only=True)
197
)
198
199
# Multiple countries as list of dictionaries
200
detailed_countries = serializers.ListField(
201
child=CountryField(country_dict=True)
202
)
203
204
# Sample output:
205
# {
206
# "operating_countries": ["US", "CA", "MX"],
207
# "operating_regions": ["United States", "Canada", "Mexico"],
208
# "detailed_countries": [
209
# {"code": "US", "name": "United States"},
210
# {"code": "CA", "name": "Canada"},
211
# {"code": "MX", "name": "Mexico"}
212
# ]
213
# }
214
```
215
216
## Advanced Usage
217
218
### Validation and Error Handling
219
220
```python
221
class StrictCountrySerializer(serializers.Serializer):
222
country = CountryField()
223
224
def validate_country(self, value):
225
"""Custom country validation."""
226
if value not in ["US", "CA", "MX"]:
227
raise serializers.ValidationError(
228
"Only North American countries are allowed"
229
)
230
return value
231
232
# Invalid country codes raise ValidationError:
233
# serializer = StrictCountrySerializer(data={"country": "INVALID"})
234
# serializer.is_valid() # False
235
# serializer.errors # {"country": ["Select a valid choice..."]}
236
```
237
238
### ViewSet Integration
239
240
```python
241
from rest_framework import viewsets
242
from rest_framework.decorators import action
243
from rest_framework.response import Response
244
245
class PersonViewSet(viewsets.ModelViewSet):
246
serializer_class = PersonModelSerializer
247
248
@action(detail=False, methods=['get'])
249
def countries(self, request):
250
"""Return list of all available countries."""
251
from django_countries import countries
252
253
country_list = [
254
{"code": country.code, "name": country.name}
255
for country in countries
256
]
257
return Response(country_list)
258
259
@action(detail=False, methods=['get'])
260
def by_country(self, request):
261
"""Filter people by country."""
262
country_code = request.query_params.get('country')
263
if country_code:
264
queryset = self.get_queryset().filter(country=country_code)
265
serializer = self.get_serializer(queryset, many=True)
266
return Response(serializer.data)
267
return Response([])
268
```
269
270
### Custom Field Behavior
271
272
```python
273
class ExtendedCountryField(CountryField):
274
"""Custom country field with additional metadata."""
275
276
def to_representation(self, obj):
277
"""Add additional country metadata."""
278
from django_countries import countries
279
280
code = countries.alpha2(obj)
281
if not code:
282
return ""
283
284
return {
285
"code": code,
286
"name": countries.name(code),
287
"alpha3": countries.alpha3(code),
288
"numeric": countries.numeric(code),
289
"flag_url": f"/static/flags/{code.lower()}.gif"
290
}
291
292
class DetailedPersonSerializer(serializers.Serializer):
293
name = serializers.CharField()
294
country = ExtendedCountryField()
295
296
# Output:
297
# {
298
# "name": "John Doe",
299
# "country": {
300
# "code": "US",
301
# "name": "United States",
302
# "alpha3": "USA",
303
# "numeric": 840,
304
# "flag_url": "/static/flags/us.gif"
305
# }
306
# }
307
```
308
309
### Filtering and Search
310
311
```python
312
from django_filter import rest_framework as filters
313
314
class PersonFilter(filters.FilterSet):
315
country = filters.CharFilter(field_name='country')
316
country_name = filters.CharFilter(
317
field_name='country',
318
lookup_expr='name_icontains'
319
)
320
321
class Meta:
322
model = Person
323
fields = ['country', 'country_name']
324
325
class PersonViewSet(viewsets.ModelViewSet):
326
serializer_class = PersonModelSerializer
327
filterset_class = PersonFilter
328
329
# URL examples:
330
# /api/people/?country=US
331
# /api/people/?country_name=united
332
```
333
334
## Integration Patterns
335
336
### API Versioning
337
338
```python
339
class PersonV1Serializer(serializers.ModelSerializer):
340
"""v1 API returns country codes only."""
341
country = CountryField()
342
343
class Meta:
344
model = Person
345
fields = ['name', 'country']
346
347
class PersonV2Serializer(serializers.ModelSerializer):
348
"""v2 API returns country with full details."""
349
country = CountryField(country_dict=True)
350
351
class Meta:
352
model = Person
353
fields = ['name', 'country']
354
```
355
356
### Nested Serialization
357
358
```python
359
class AddressSerializer(serializers.Serializer):
360
street = serializers.CharField()
361
city = serializers.CharField()
362
country = CountryField(country_dict=True)
363
364
class PersonWithAddressSerializer(serializers.Serializer):
365
name = serializers.CharField()
366
address = AddressSerializer()
367
368
# Output:
369
# {
370
# "name": "John Doe",
371
# "address": {
372
# "street": "123 Main St",
373
# "city": "New York",
374
# "country": {"code": "US", "name": "United States"}
375
# }
376
# }
377
```
378
379
### Performance Optimization
380
381
```python
382
class OptimizedPersonSerializer(serializers.ModelSerializer):
383
"""Optimized serializer for bulk operations."""
384
385
# Use code-only for better performance in lists
386
country = CountryField()
387
388
def to_representation(self, instance):
389
"""Add country name only when needed."""
390
data = super().to_representation(instance)
391
392
# Add country name for detail views
393
if self.context.get('detail_view'):
394
from django_countries import countries
395
data['country_name'] = countries.name(data['country'])
396
397
return data
398
```