or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

exceptions-utilities.mdfiltering.mdindex.mdpagination.mdrelations.mdrenderers-parsers.mdserializers.mdviews.md

relations.mddocs/

0

# Relations

1

2

Resource relationship fields that handle JSON:API resource identifier objects, hyperlinked relationships, and relationship data management with support for both to-one and to-many relationships.

3

4

## Capabilities

5

6

### ResourceRelatedField

7

8

Main relationship field for JSON:API resource relationships.

9

10

```python { .api }

11

class ResourceRelatedField(RelatedField):

12

"""

13

JSON:API resource relationship field.

14

15

Handles relationships as resource identifier objects:

16

{"type": "resource-type", "id": "123"}

17

18

Supports both to-one and to-many relationships with proper

19

JSON:API formatting and validation.

20

"""

21

22

queryset = None # QuerySet for related objects

23

many = False # True for to-many relationships

24

read_only = False # Whether field is read-only

25

required = True # Whether field is required

26

allow_null = False # Whether null values are allowed

27

28

def __init__(self, **kwargs):

29

"""

30

Initialize resource relationship field.

31

32

Args:

33

queryset: QuerySet for related objects

34

many: True for to-many relationships

35

read_only: Whether field is read-only

36

required: Whether field is required

37

allow_null: Whether null values allowed

38

"""

39

40

def to_representation(self, value):

41

"""

42

Convert related object(s) to resource identifier object(s).

43

44

Args:

45

value: Related Django model instance or QuerySet

46

47

Returns:

48

dict or list: Resource identifier object(s)

49

"""

50

51

def to_internal_value(self, data):

52

"""

53

Convert resource identifier object(s) to Django model instance(s).

54

55

Args:

56

data: Resource identifier object(s)

57

58

Returns:

59

Model instance or list of instances

60

61

Raises:

62

ValidationError: If resource type doesn't match or objects don't exist

63

"""

64

65

def get_attribute(self, instance):

66

"""Get related object(s) from model instance."""

67

```

68

69

Usage example:

70

71

```python

72

from rest_framework_json_api import serializers

73

from rest_framework_json_api.relations import ResourceRelatedField

74

from myapp.models import Article, Author, Tag

75

76

class ArticleSerializer(serializers.ModelSerializer):

77

author = ResourceRelatedField(queryset=Author.objects.all())

78

tags = ResourceRelatedField(queryset=Tag.objects.all(), many=True)

79

80

class Meta:

81

model = Article

82

fields = ['title', 'content', 'author', 'tags']

83

84

# Generates relationships:

85

# {

86

# "relationships": {

87

# "author": {

88

# "data": {"type": "authors", "id": "5"}

89

# },

90

# "tags": {

91

# "data": [

92

# {"type": "tags", "id": "1"},

93

# {"type": "tags", "id": "2"}

94

# ]

95

# }

96

# }

97

# }

98

```

99

100

### HyperlinkedMixin

101

102

Mixin that adds hyperlink support to relationship fields.

103

104

```python { .api }

105

class HyperlinkedMixin:

106

"""

107

Mixin for hyperlinked relationship fields.

108

109

Adds self and related links to relationship objects:

110

{

111

"data": {"type": "authors", "id": "5"},

112

"links": {

113

"self": "/articles/1/relationships/author",

114

"related": "/articles/1/author"

115

}

116

}

117

"""

118

119

self_link_view_name = None # View name for self link

120

related_link_view_name = None # View name for related link

121

related_link_lookup_field = 'pk' # Lookup field for related link

122

related_link_url_kwarg = None # URL kwarg name

123

124

def __init__(self, self_link_view_name=None, related_link_view_name=None, **kwargs):

125

"""

126

Initialize hyperlinked mixin.

127

128

Args:

129

self_link_view_name: View name for relationship self link

130

related_link_view_name: View name for related resource link

131

"""

132

133

def get_url(self, name, view_name, kwargs, request):

134

"""

135

Generate URL for hyperlinked relationship.

136

137

Args:

138

name: Link name ('self' or 'related')

139

view_name: Django URL view name

140

kwargs: URL kwargs

141

request: HTTP request object

142

143

Returns:

144

str or None: Generated URL

145

"""

146

147

def get_links(self, obj=None, lookup_field='pk'):

148

"""

149

Generate links dict for relationship.

150

151

Args:

152

obj: Related object instance

153

lookup_field: Field to use for lookup

154

155

Returns:

156

dict: Links with self and/or related URLs

157

"""

158

```

159

160

### SerializerMethodResourceRelatedField

161

162

Resource relationship field that uses a serializer method.

163

164

```python { .api }

165

class SerializerMethodResourceRelatedField(Field):

166

"""

167

Resource relationship field that gets its value from a serializer method.

168

169

Similar to SerializerMethodField but for relationships.

170

Returns resource identifier objects.

171

"""

172

173

def __init__(self, method_name=None, **kwargs):

174

"""

175

Initialize method-based resource field.

176

177

Args:

178

method_name: Name of serializer method to call

179

"""

180

181

def to_representation(self, obj):

182

"""

183

Get relationship value from serializer method.

184

185

Args:

186

obj: Object being serialized

187

188

Returns:

189

dict or list: Resource identifier object(s)

190

"""

191

```

192

193

Usage example:

194

195

```python

196

class ArticleSerializer(serializers.ModelSerializer):

197

featured_comments = SerializerMethodResourceRelatedField()

198

199

def get_featured_comments(self, obj):

200

# Return featured comments for this article

201

return obj.comments.filter(featured=True)

202

```

203

204

### ManySerializerMethodResourceRelatedField

205

206

Many-to-many version of SerializerMethodResourceRelatedField.

207

208

```python { .api }

209

class ManySerializerMethodResourceRelatedField(SerializerMethodResourceRelatedField):

210

"""

211

Many-to-many version of SerializerMethodResourceRelatedField.

212

213

Always returns a list of resource identifier objects.

214

"""

215

216

many = True # Always True for this field type

217

```

218

219

### SkipDataMixin

220

221

Mixin that skips data rendering for performance optimization.

222

223

```python { .api }

224

class SkipDataMixin:

225

"""

226

Mixin that skips "data" rendering in relationships for performance.

227

228

Useful when you only want to include relationship links

229

without the actual relationship data to save database queries.

230

"""

231

232

def get_attribute(self, instance):

233

"""Skip field to avoid database queries."""

234

raise SkipField

235

236

def to_representation(self, *args):

237

"""Not implemented - data is skipped."""

238

raise NotImplementedError

239

```

240

241

### PolymorphicResourceRelatedField

242

243

Resource relationship field for polymorphic models.

244

245

```python { .api }

246

class PolymorphicResourceRelatedField(ResourceRelatedField):

247

"""

248

Resource relationship field for polymorphic models.

249

250

Handles relationships to polymorphic models that can represent

251

multiple resource types with proper type detection.

252

"""

253

```

254

255

### HyperlinkedRelatedField

256

257

Hyperlinked relationship field that only provides links.

258

259

```python { .api }

260

class HyperlinkedRelatedField(HyperlinkedMixin, SkipDataMixin, RelatedField):

261

"""

262

Hyperlinked relationship field that skips data and only provides links.

263

264

Useful for providing relationship links without fetching relationship data

265

for performance optimization.

266

"""

267

```

268

269

### SerializerMethodHyperlinkedRelatedField

270

271

Hyperlinked relationship field that uses a serializer method.

272

273

```python { .api }

274

class SerializerMethodHyperlinkedRelatedField(HyperlinkedMixin, SerializerMethodFieldBase):

275

"""

276

Hyperlinked relationship field that gets its value from a serializer method.

277

278

Combines method-based value retrieval with hyperlink generation.

279

"""

280

```

281

282

### ManySerializerMethodHyperlinkedRelatedField

283

284

Many-to-many version of SerializerMethodHyperlinkedRelatedField.

285

286

```python { .api }

287

class ManySerializerMethodHyperlinkedRelatedField(SerializerMethodHyperlinkedRelatedField):

288

"""

289

Many-to-many version of SerializerMethodHyperlinkedRelatedField.

290

291

Always returns a list of hyperlinked relationships.

292

"""

293

294

many = True

295

```

296

297

### ManyRelatedFieldWithNoData

298

299

Many-to-many field that skips data rendering.

300

301

```python { .api }

302

class ManyRelatedFieldWithNoData(SkipDataMixin, DRFManyRelatedField):

303

"""

304

Many-to-many relationship field that skips data for performance.

305

306

Only includes relationship links, not the actual relationship data.

307

Useful for relationships that would cause expensive database queries.

308

"""

309

```

310

311

## Relationship Types

312

313

### To-One Relationships

314

315

```python

316

# ForeignKey field

317

class ArticleSerializer(serializers.ModelSerializer):

318

author = ResourceRelatedField(queryset=Author.objects.all())

319

320

# Generates:

321

# {

322

# "relationships": {

323

# "author": {

324

# "data": {"type": "authors", "id": "5"}

325

# }

326

# }

327

# }

328

```

329

330

### To-Many Relationships

331

332

```python

333

# ManyToMany or reverse ForeignKey field

334

class ArticleSerializer(serializers.ModelSerializer):

335

tags = ResourceRelatedField(queryset=Tag.objects.all(), many=True)

336

comments = ResourceRelatedField(source='comment_set', many=True, read_only=True)

337

338

# Generates:

339

# {

340

# "relationships": {

341

# "tags": {

342

# "data": [

343

# {"type": "tags", "id": "1"},

344

# {"type": "tags", "id": "2"}

345

# ]

346

# },

347

# "comments": {

348

# "data": [

349

# {"type": "comments", "id": "10"},

350

# {"type": "comments", "id": "11"}

351

# ]

352

# }

353

# }

354

# }

355

```

356

357

### Hyperlinked Relationships

358

359

```python

360

class ArticleAuthorField(HyperlinkedMixin, ResourceRelatedField):

361

self_link_view_name = 'article-relationships-author'

362

related_link_view_name = 'article-author'

363

364

class ArticleSerializer(serializers.ModelSerializer):

365

author = ArticleAuthorField(queryset=Author.objects.all())

366

367

# Generates:

368

# {

369

# "relationships": {

370

# "author": {

371

# "data": {"type": "authors", "id": "5"},

372

# "links": {

373

# "self": "/articles/1/relationships/author",

374

# "related": "/articles/1/author"

375

# }

376

# }

377

# }

378

# }

379

```

380

381

### Null Relationships

382

383

```python

384

# Allow null relationships

385

class ArticleSerializer(serializers.ModelSerializer):

386

author = ResourceRelatedField(

387

queryset=Author.objects.all(),

388

allow_null=True,

389

required=False

390

)

391

392

# When author is None:

393

# {

394

# "relationships": {

395

# "author": {

396

# "data": null

397

# }

398

# }

399

# }

400

```

401

402

## Performance Optimization

403

404

```python

405

# Skip relationship data for performance

406

class ArticleSerializer(serializers.ModelSerializer):

407

# Only include links, not data

408

expensive_relation = ManyRelatedFieldWithNoData()

409

410

# Or use custom field with SkipDataMixin

411

class OptimizedRelationField(SkipDataMixin, ResourceRelatedField):

412

pass

413

414

author = OptimizedRelationField()

415

416

# Generates relationship with links only:

417

# {

418

# "relationships": {

419

# "author": {

420

# "links": {

421

# "self": "/articles/1/relationships/author",

422

# "related": "/articles/1/author"

423

# }

424

# }

425

# }

426

# }

427

```

428

429

## Error Handling

430

431

Relationship fields provide proper validation errors:

432

433

```python

434

# Invalid resource type:

435

# {

436

# "errors": [{

437

# "detail": "Incorrect model type. Expected authors, received users.",

438

# "source": {"pointer": "/data/relationships/author"}

439

# }]

440

# }

441

442

# Object doesn't exist:

443

# {

444

# "errors": [{

445

# "detail": "Invalid pk \"999\" - object does not exist.",

446

# "source": {"pointer": "/data/relationships/author"}

447

# }]

448

# }

449

```

450

451

## Types

452

453

```python { .api }

454

from rest_framework_json_api.relations import (

455

ResourceRelatedField,

456

HyperlinkedMixin,

457

SerializerMethodResourceRelatedField,

458

ManySerializerMethodResourceRelatedField,

459

SkipDataMixin,

460

ManyRelatedFieldWithNoData

461

)

462

463

# Constants

464

LINKS_PARAMS = [

465

"self_link_view_name",

466

"related_link_view_name",

467

"related_link_lookup_field",

468

"related_link_url_kwarg"

469

]

470

```