0
# Django REST Framework Integration
1
2
Django Simple Captcha provides dedicated serializers for integrating captcha validation into Django REST Framework APIs. These serializers enable captcha protection for API endpoints while maintaining the same validation logic as form-based implementations.
3
4
## Capabilities
5
6
### CaptchaSerializer
7
8
Standalone serializer for API endpoints that need captcha validation without being tied to a specific model.
9
10
```python { .api }
11
class CaptchaSerializer(serializers.Serializer):
12
captcha_code = serializers.CharField(max_length=32, write_only=True, required=True)
13
captcha_hashkey = serializers.CharField(max_length=40, write_only=True, required=True)
14
15
def run_validation(data=empty):
16
"""
17
Validate captcha data (captcha fields remain in validated data).
18
19
Parameters:
20
- data: dict, input data containing captcha_code and captcha_hashkey
21
22
Returns:
23
dict: Validated data including captcha fields
24
25
Raises:
26
ValidationError: If captcha validation fails or fields are missing
27
"""
28
```
29
30
### CaptchaModelSerializer
31
32
Model serializer that includes captcha validation for API endpoints that work with Django model instances.
33
34
```python { .api }
35
class CaptchaModelSerializer(serializers.ModelSerializer):
36
captcha_code = serializers.CharField(max_length=32, write_only=True, required=True)
37
captcha_hashkey = serializers.CharField(max_length=40, write_only=True, required=True)
38
39
def run_validation(data=empty):
40
"""
41
Validate captcha data (captcha fields remain in validated data).
42
43
Parameters:
44
- data: dict, input data containing model fields plus captcha fields
45
46
Returns:
47
dict: Validated data including captcha fields
48
49
Raises:
50
ValidationError: If captcha validation fails or model validation fails
51
"""
52
```
53
54
## Usage Examples
55
56
### Basic API View with Captcha
57
58
```python
59
from rest_framework.views import APIView
60
from rest_framework.response import Response
61
from rest_framework import status
62
from captcha.serializers import CaptchaSerializer
63
from captcha.models import CaptchaStore
64
65
class ContactAPIView(APIView):
66
def get(self, request):
67
"""Generate new captcha for the form."""
68
captcha_key = CaptchaStore.generate_key()
69
return Response({
70
'captcha_key': captcha_key,
71
'captcha_image_url': f'/captcha/image/{captcha_key}/',
72
'captcha_audio_url': f'/captcha/audio/{captcha_key}.wav',
73
})
74
75
def post(self, request):
76
"""Process contact form with captcha validation."""
77
# Create a combined serializer
78
class ContactSerializer(CaptchaSerializer):
79
name = serializers.CharField(max_length=100)
80
email = serializers.EmailField()
81
message = serializers.CharField()
82
83
serializer = ContactSerializer(data=request.data)
84
if serializer.is_valid():
85
# Captcha was validated automatically
86
contact_data = serializer.validated_data
87
# Process contact form (send email, save to database, etc.)
88
return Response({'status': 'success'}, status=status.HTTP_200_OK)
89
90
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
91
```
92
93
### Model-Based API with Captcha
94
95
```python
96
from rest_framework import generics
97
from django.contrib.auth.models import User
98
from captcha.serializers import CaptchaModelSerializer
99
100
class UserRegistrationSerializer(CaptchaModelSerializer):
101
password = serializers.CharField(write_only=True)
102
103
class Meta:
104
model = User
105
fields = ['username', 'email', 'password', 'captcha_code', 'captcha_hashkey']
106
107
def create(self, validated_data):
108
# Captcha fields are already removed by run_validation
109
password = validated_data.pop('password')
110
user = User.objects.create_user(**validated_data)
111
user.set_password(password)
112
user.save()
113
return user
114
115
class UserRegistrationView(generics.CreateAPIView):
116
serializer_class = UserRegistrationSerializer
117
queryset = User.objects.all()
118
```
119
120
### ViewSet with Captcha Protection
121
122
```python
123
from rest_framework import viewsets, decorators
124
from rest_framework.response import Response
125
from captcha.models import CaptchaStore
126
from captcha.serializers import CaptchaModelSerializer
127
128
class CommentViewSet(viewsets.ModelViewSet):
129
queryset = Comment.objects.all()
130
131
def get_serializer_class(self):
132
if self.action == 'create':
133
# Use captcha protection for comment creation
134
class CommentCaptchaSerializer(CaptchaModelSerializer):
135
class Meta:
136
model = Comment
137
fields = ['content', 'captcha_code', 'captcha_hashkey']
138
return CommentCaptchaSerializer
139
return CommentSerializer
140
141
@decorators.action(detail=False, methods=['get'])
142
def captcha(self, request):
143
"""Get new captcha for comment form."""
144
captcha_key = CaptchaStore.generate_key()
145
return Response({
146
'captcha_key': captcha_key,
147
'captcha_image_url': f'/captcha/image/{captcha_key}/',
148
})
149
```
150
151
### Custom Validation Logic
152
153
```python
154
from captcha.serializers import CaptchaSerializer
155
from captcha.validators import captcha_validate
156
from django.core.exceptions import ValidationError
157
158
class CustomCaptchaSerializer(serializers.Serializer):
159
email = serializers.EmailField()
160
captcha_code = serializers.CharField(max_length=32)
161
captcha_hashkey = serializers.CharField(max_length=40)
162
163
def validate(self, data):
164
"""Custom captcha validation with additional logic."""
165
try:
166
captcha_validate(data['captcha_hashkey'], data['captcha_code'])
167
except ValidationError as e:
168
raise serializers.ValidationError({'captcha': e.message})
169
170
# Remove captcha fields from validated data
171
data.pop('captcha_code', None)
172
data.pop('captcha_hashkey', None)
173
174
# Additional custom validation
175
email = data.get('email')
176
if User.objects.filter(email=email).exists():
177
raise serializers.ValidationError({'email': 'Email already exists'})
178
179
return data
180
```
181
182
### AJAX Frontend Integration
183
184
```javascript
185
// JavaScript for API captcha integration
186
class CaptchaAPI {
187
constructor() {
188
this.captchaData = null;
189
}
190
191
async loadCaptcha() {
192
const response = await fetch('/api/contact/', {
193
method: 'GET',
194
headers: {
195
'Content-Type': 'application/json',
196
},
197
});
198
199
this.captchaData = await response.json();
200
201
// Update UI with new captcha
202
document.getElementById('captcha-image').src = this.captchaData.captcha_image_url;
203
document.getElementById('captcha-key').value = this.captchaData.captcha_key;
204
}
205
206
async submitForm(formData) {
207
// Add captcha data to form
208
formData.captcha_hashkey = this.captchaData.captcha_key;
209
formData.captcha_code = document.getElementById('captcha-input').value;
210
211
const response = await fetch('/api/contact/', {
212
method: 'POST',
213
headers: {
214
'Content-Type': 'application/json',
215
'X-CSRFToken': getCookie('csrftoken'),
216
},
217
body: JSON.stringify(formData),
218
});
219
220
if (response.ok) {
221
alert('Form submitted successfully!');
222
} else {
223
const errors = await response.json();
224
if (errors.captcha) {
225
// Refresh captcha on validation error
226
await this.loadCaptcha();
227
alert('Captcha validation failed. Please try again.');
228
}
229
}
230
}
231
}
232
233
// Usage
234
const captchaAPI = new CaptchaAPI();
235
captchaAPI.loadCaptcha();
236
```
237
238
### Batch Operations with Captcha
239
240
```python
241
from rest_framework import serializers
242
from captcha.serializers import CaptchaSerializer
243
244
class BulkCreateSerializer(CaptchaSerializer):
245
items = serializers.ListField(
246
child=serializers.DictField(),
247
min_length=1,
248
max_length=10
249
)
250
251
def create(self, validated_data):
252
# Captcha already validated, process bulk creation
253
items_data = validated_data['items']
254
created_items = []
255
256
for item_data in items_data:
257
item = MyModel.objects.create(**item_data)
258
created_items.append(item)
259
260
return created_items
261
```
262
263
## API Response Format
264
265
When captcha validation fails, the API returns standard DRF validation error format:
266
267
```json
268
{
269
"captcha_code": ["This field is required."],
270
"captcha_hashkey": ["Invalid captcha."]
271
}
272
```
273
274
Successful validation removes captcha fields from the response, returning only the relevant model/business data.
275
276
## Integration Notes
277
278
- Captcha fields are automatically marked as `write_only=True`
279
- Captcha validation occurs before model validation
280
- Failed captcha validation prevents the request from proceeding
281
- Captcha fields are removed from `validated_data` after successful validation
282
- Both serializers work with the same captcha generation and validation backend as form-based views