or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth-permissions.mdcontent-negotiation.mddecorators.mdfields-validation.mdgeneric-views.mdindex.mdpagination-filtering.mdrequest-response.mdrouters-urls.mdserializers.mdstatus-exceptions.mdtesting.mdviews-viewsets.md

request-response.mddocs/

0

# Request and Response

1

2

Enhanced request and response objects providing consistent data access and content negotiation across different formats in Django REST Framework.

3

4

## Capabilities

5

6

### Request Object

7

8

Enhanced request object wrapping Django's HttpRequest with additional API functionality.

9

10

```python { .api }

11

class Request:

12

"""

13

Enhanced request object with additional API features.

14

"""

15

def __init__(self, request, parsers=None, authenticators=None,

16

negotiator=None, parser_context=None):

17

"""

18

Initialize DRF Request object.

19

20

Args:

21

request: Django HttpRequest object

22

parsers (list): List of parser instances

23

authenticators (list): List of authenticator instances

24

negotiator: Content negotiation instance

25

parser_context (dict): Additional context for parsers

26

"""

27

28

@property

29

def data(self):

30

"""

31

Parsed request body data.

32

33

Returns:

34

dict or list: Parsed data from request body

35

"""

36

37

@property

38

def query_params(self):

39

"""

40

Query parameters from URL (more semantic than request.GET).

41

42

Returns:

43

QueryDict: URL query parameters

44

"""

45

46

@property

47

def user(self):

48

"""

49

Authenticated user for this request.

50

51

Returns:

52

User instance or AnonymousUser

53

"""

54

55

@property

56

def auth(self):

57

"""

58

Authentication credentials for this request.

59

60

Returns:

61

Authentication token/credentials or None

62

"""

63

64

@property

65

def successful_authenticator(self):

66

"""

67

Authenticator instance that successfully authenticated the request.

68

69

Returns:

70

Authentication instance or None

71

"""

72

73

@property

74

def accepted_renderer(self):

75

"""

76

Renderer selected by content negotiation.

77

78

Returns:

79

Renderer instance

80

"""

81

82

@property

83

def accepted_media_type(self):

84

"""

85

Media type selected by content negotiation.

86

87

Returns:

88

str: Media type string

89

"""

90

91

@property

92

def version(self):

93

"""

94

API version for this request.

95

96

Returns:

97

str: Version string or None

98

"""

99

100

@property

101

def versioning_scheme(self):

102

"""

103

Versioning scheme instance for this request.

104

105

Returns:

106

Versioning scheme instance or None

107

"""

108

```

109

110

### Response Object

111

112

Enhanced response object for API responses with content negotiation support.

113

114

```python { .api }

115

class Response(SimpleTemplateResponse):

116

"""

117

Enhanced response object for API responses.

118

"""

119

def __init__(self, data=None, status=None, template_name=None,

120

headers=None, exception=False, content_type=None):

121

"""

122

Initialize API response.

123

124

Args:

125

data: Response data (will be serialized)

126

status (int): HTTP status code

127

template_name (str): Template for HTML rendering

128

headers (dict): Additional response headers

129

exception (bool): Whether response is for exception

130

content_type (str): Response content type

131

"""

132

133

@property

134

def data(self):

135

"""

136

Response data to be serialized.

137

138

Returns:

139

Response data

140

"""

141

142

@data.setter

143

def data(self, value):

144

"""

145

Set response data.

146

147

Args:

148

value: Data to serialize in response

149

"""

150

151

@property

152

def status_code(self):

153

"""

154

HTTP status code for response.

155

156

Returns:

157

int: HTTP status code

158

"""

159

160

@status_code.setter

161

def status_code(self, value):

162

"""

163

Set HTTP status code.

164

165

Args:

166

value (int): HTTP status code

167

"""

168

169

@property

170

def status_text(self):

171

"""

172

HTTP status text for response.

173

174

Returns:

175

str: HTTP status text

176

"""

177

178

@property

179

def rendered_content(self):

180

"""

181

Rendered response content.

182

183

Returns:

184

bytes: Rendered content

185

"""

186

```

187

188

### Request Utilities

189

190

Utility classes and functions for request handling.

191

192

```python { .api }

193

class ForcedAuthentication:

194

"""

195

Force specific user authentication for testing.

196

"""

197

def __init__(self, user, token=None):

198

"""

199

Args:

200

user: User instance to authenticate as

201

token: Optional authentication token

202

"""

203

self.user = user

204

self.token = token

205

206

class Empty:

207

"""

208

Placeholder for empty request data.

209

"""

210

pass

211

212

def is_form_media_type(media_type):

213

"""

214

Check if media type represents form data.

215

216

Args:

217

media_type (str): Media type to check

218

219

Returns:

220

bool: True if form media type

221

"""

222

223

def clone_request(request, method):

224

"""

225

Clone request with different HTTP method.

226

227

Args:

228

request: Original request object

229

method (str): New HTTP method

230

231

Returns:

232

Request: Cloned request with new method

233

"""

234

235

class override_method:

236

"""

237

Context manager for temporarily overriding request method.

238

"""

239

def __init__(self, request, method):

240

"""

241

Args:

242

request: Request object to modify

243

method (str): Temporary method to use

244

"""

245

self.request = request

246

self.method = method

247

self.original_method = None

248

249

def __enter__(self):

250

"""Enter context with overridden method."""

251

return self

252

253

def __exit__(self, exc_type, exc_val, exc_tb):

254

"""Restore original method."""

255

```

256

257

## Usage Examples

258

259

### Accessing Request Data

260

261

```python

262

from rest_framework.views import APIView

263

from rest_framework.response import Response

264

265

class BookView(APIView):

266

def post(self, request):

267

# Access parsed request data (JSON, form data, etc.)

268

title = request.data.get('title')

269

author = request.data.get('author')

270

271

# Access query parameters

272

format_type = request.query_params.get('format', 'json')

273

274

# Access authenticated user

275

user = request.user

276

277

# Access authentication token/credentials

278

auth_token = request.auth

279

280

# Create response

281

response_data = {

282

'message': f'Book "{title}" by {author} created',

283

'user': user.username if user.is_authenticated else 'anonymous',

284

'format': format_type

285

}

286

287

return Response(response_data, status=201)

288

```

289

290

### Different Response Types

291

292

```python

293

from rest_framework.response import Response

294

from rest_framework import status

295

296

class BookAPIView(APIView):

297

def get(self, request):

298

# Simple data response

299

data = {'books': ['Book 1', 'Book 2']}

300

return Response(data)

301

302

def post(self, request):

303

# Response with custom status

304

return Response(

305

{'message': 'Book created'},

306

status=status.HTTP_201_CREATED

307

)

308

309

def put(self, request):

310

# Response with custom headers

311

headers = {'X-Custom-Header': 'custom-value'}

312

return Response(

313

{'message': 'Book updated'},

314

headers=headers

315

)

316

317

def delete(self, request):

318

# Empty response with status code

319

return Response(status=status.HTTP_204_NO_CONTENT)

320

```

321

322

### Content Negotiation

323

324

```python

325

class BookView(APIView):

326

def get(self, request):

327

books = Book.objects.all()

328

329

# Check accepted media type

330

if request.accepted_media_type == 'application/json':

331

# JSON response

332

serializer = BookSerializer(books, many=True)

333

return Response(serializer.data)

334

elif request.accepted_media_type == 'text/html':

335

# HTML response

336

return Response(

337

{'books': books},

338

template_name='books/list.html'

339

)

340

else:

341

# Default response

342

return Response({'error': 'Unsupported media type'})

343

```

344

345

### API Versioning

346

347

API versioning allows maintaining backward compatibility while evolving APIs. Multiple versioning strategies are supported.

348

349

#### Versioning Classes

350

351

```python { .api }

352

class BaseVersioning:

353

"""

354

Base class for all versioning schemes.

355

"""

356

default_version = None

357

allowed_versions = None

358

version_param = 'version'

359

360

def determine_version(self, request, *args, **kwargs):

361

"""

362

Determine API version from request.

363

Must be implemented by subclasses.

364

365

Returns:

366

str: Version string

367

"""

368

369

def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):

370

"""

371

Reverse URL with version information.

372

"""

373

374

class AcceptHeaderVersioning(BaseVersioning):

375

"""

376

Version determined from Accept header media type parameters.

377

Example: Accept: application/json; version=1.0

378

"""

379

380

class URLPathVersioning(BaseVersioning):

381

"""

382

Version determined from URL path keyword arguments.

383

Example: /v1/books/

384

"""

385

386

class NamespaceVersioning(BaseVersioning):

387

"""

388

Version determined from URL namespace.

389

Example: URL patterns with version namespaces

390

"""

391

392

class HostNameVersioning(BaseVersioning):

393

"""

394

Version determined from request hostname.

395

Example: v1.api.example.com

396

"""

397

398

class QueryParameterVersioning(BaseVersioning):

399

"""

400

Version determined from query parameters.

401

Example: /books/?version=1.0

402

"""

403

```

404

405

#### Versioning Configuration

406

407

Configure versioning in Django settings:

408

409

```python

410

# settings.py

411

REST_FRAMEWORK = {

412

'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning',

413

'DEFAULT_VERSION': '1.0',

414

'ALLOWED_VERSIONS': ['1.0', '1.1', '2.0'],

415

'VERSION_PARAM': 'version',

416

}

417

```

418

419

#### URL Path Versioning Example

420

421

```python

422

# urls.py

423

from django.urls import path, include

424

425

urlpatterns = [

426

path('v1/', include('myapp.urls', namespace='v1')),

427

path('v2/', include('myapp.urls', namespace='v2')),

428

]

429

430

# Using in views

431

class BookViewSet(ModelViewSet):

432

def list(self, request):

433

version = request.version

434

435

if version == '1.0':

436

# Version 1.0 response format

437

serializer = BookSerializerV1(books, many=True)

438

elif version == '2.0':

439

# Version 2.0 response format

440

serializer = BookSerializerV2(books, many=True)

441

442

return Response(serializer.data)

443

```

444

445

#### Accept Header Versioning Example

446

447

```python

448

# Client request:

449

# Accept: application/json; version=1.1

450

451

class BookAPIView(APIView):

452

def get(self, request):

453

version = request.version # '1.1'

454

455

books = Book.objects.all()

456

if version == '1.0':

457

data = [{'id': b.id, 'title': b.title} for b in books]

458

else: # version >= 1.1

459

data = [{'id': b.id, 'title': b.title, 'author': b.author} for b in books]

460

461

return Response({'books': data, 'version': version})

462

```

463

464

#### Custom Versioning Scheme

465

466

```python

467

from rest_framework.versioning import BaseVersioning

468

from rest_framework import exceptions

469

470

class CustomHeaderVersioning(BaseVersioning):

471

"""

472

Custom versioning based on X-API-Version header.

473

"""

474

def determine_version(self, request, *args, **kwargs):

475

version = request.META.get('HTTP_X_API_VERSION', self.default_version)

476

477

if not self.is_allowed_version(version):

478

raise exceptions.NotAcceptable(

479

'Invalid API version. Supported versions: {}'.format(

480

', '.join(self.allowed_versions)

481

)

482

)

483

484

return version

485

```

486

487

### Working with File Uploads

488

489

```python

490

class FileUploadView(APIView):

491

def post(self, request):

492

# Access uploaded files

493

uploaded_file = request.data.get('file')

494

495

if uploaded_file:

496

# Process the file

497

file_content = uploaded_file.read()

498

file_name = uploaded_file.name

499

file_size = uploaded_file.size

500

501

return Response({

502

'message': 'File uploaded successfully',

503

'filename': file_name,

504

'size': file_size

505

})

506

507

return Response(

508

{'error': 'No file provided'},

509

status=status.HTTP_400_BAD_REQUEST

510

)

511

```

512

513

### Request Method Override

514

515

```python

516

from rest_framework.request import override_method

517

518

class CustomView(APIView):

519

def post(self, request):

520

# Temporarily override method for internal processing

521

with override_method(request, 'PUT'):

522

# Process as if it were a PUT request

523

return self.handle_update(request)

524

525

def handle_update(self, request):

526

# Method sees request.method as 'PUT'

527

return Response({'method': request.method})

528

```

529

530

### Testing with Forced Authentication

531

532

```python

533

from rest_framework.request import ForcedAuthentication

534

from rest_framework.test import APIRequestFactory

535

536

# In tests

537

factory = APIRequestFactory()

538

user = User.objects.create_user('testuser')

539

540

# Create request with forced authentication

541

request = factory.post('/api/books/', {'title': 'Test Book'})

542

force_auth = ForcedAuthentication(user)

543

544

# Apply authentication

545

request.user = user

546

request.auth = None

547

```