Skip to content

Add SerializedRelatedField for write-by-slug, read-as-nested representation - #9784

Closed
HosseinSayyedMousavi wants to merge 1 commit into
encode:mainfrom
HosseinSayyedMousavi:feature/serialized-slug-related-field
Closed

HosseinSayyedMousavi wants to merge 1 commit into
encode:mainfrom
HosseinSayyedMousavi:feature/serialized-slug-related-field

Conversation

@HosseinSayyedMousavi

@HosseinSayyedMousavi HosseinSayyedMousavi commented Sep 19, 2025 •

Copy link
Copy Markdown

Add FlexibleField and SerializedRelatedField for independent read/write representations

Description

Currently, DRF fields generally define both input validation and output representation as part of the same field implementation. However, some API use cases require different behavior when reading and writing a value.

For example, an API may need to accept a simple identifier when writing a related object, while returning its full serialized representation when reading it. Similarly, input and output may require different field types or formats.

This PR introduces two fields to address these use cases:

  • FlexibleField allows input validation and output representation to be configured independently using separate field instances.
  • SerializedRelatedField provides a convenient relational field that accepts a related object's slug or primary key on writes and returns its serialized representation on reads.

FlexibleField

FlexibleField provides a general-purpose abstraction for combining different field implementations for input and output.

For example, an API can accept a primary key when writing an address while returning a nested representation when reading it:

address = FlexibleField(
    read=AddressSerializer(),
    write=serializers.PrimaryKeyRelatedField(
        queryset=Address.objects.all(),
    ),
)

This approach can also support other combinations, such as different input and output formats or simple input values with structured output representations, without being limited to relational fields.

SerializedRelatedField

SerializedRelatedField addresses a common relational-field use case: accepting a simple value to identify a related object while returning its full serialized representation.

For example:

address = SerializedRelatedField(
    serializer_class=AddressSerializer,
    queryset=Address.objects.all(),
    lookup_field="postal_code",
)

A request can provide a simple value:

{
    "address": "12345"
}

The response can return the serialized address:

{
    "address": {
        "id": 1,
        "postal_code": "12345",
        "province": "Tehran",
        "city": "Tehran",
        "street": "Valiasr",
        "additional_info": "Test info"
    }
}

The lookup_field option determines which field is used to resolve the related object during input validation.

Testing

The implementation is tested using django.test.TestCase.

The tests cover:

  • Writing related objects using a slug or primary key and reading their serialized representations.
  • Configuring independent field implementations for input and output.
  • Using different input and output formats, including date/time representations.
  • Combining simple input values with structured output representations.
  • Input validation and read-only/write-only behavior.
  • Invalid and ambiguous related-object lookups.

@HosseinSayyedMousavi
HosseinSayyedMousavi force-pushed the feature/serialized-slug-related-field branch from 4c7ab6e to 67a800b Compare September 19, 2025 21:22
@auvipy
auvipy self-requested a review September 20, 2025 11:53
@p-r-a-v-i-n

Copy link
Copy Markdown
Contributor

DRF is considered to be featured complete as per the contributing guidlines.
https://www.django-rest-framework.org/community/contributing

@HosseinSayyedMousavi
HosseinSayyedMousavi force-pushed the feature/serialized-slug-related-field branch from 67a800b to 97a6631 Compare June 4, 2026 08:01
@HosseinSayyedMousavi
HosseinSayyedMousavi force-pushed the feature/serialized-slug-related-field branch 4 times, most recently from 97a6631 to 1aa549e Compare October 8, 2026 07:01
…tation

- Introduce SerializedRelatedField in rest_framework/relations.py
- Supports writing by slug/PK and reading as nested serializer
- Add corresponding tests in tests/test_relations.py
@HosseinSayyedMousavi
HosseinSayyedMousavi force-pushed the feature/serialized-slug-related-field branch from 1aa549e to 687e8b9 Compare October 8, 2026 07:14
@browniebroke

Copy link
Copy Markdown
Member

DRF is considered to be featured complete as per the contributing guidlines. https://www.django-rest-framework.org/community/contributing

Agree, that feels out of scope of our policy.

@merwok

merwok commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

This is a common need, I was hoping to see this reconsidered with the move to django-commons 🙁

@HosseinSayyedMousavi

HosseinSayyedMousavi commented Oct 10, 2026 •

Copy link
Copy Markdown
Author

This is a common need, I was hoping to see this reconsidered with the move to django-commons 🙁

Thanks Éric for your comment. I'm glad to hear that you consider this a common need.

I'd still like to explore whether this feature could be included in DRF itself, rather than maintained as a separate package.

Do you think there's a reasonable case for reconsidering it within DRF's current scope? If so, I'd appreciate your thoughts on how best to bring this up with the maintainers.

@auvipy

auvipy commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

i think this is better suited for drf extensions https://github.com/chibisov/drf-extensions . open a pr there and ping me if you want

@HosseinSayyedMousavi

HosseinSayyedMousavi commented Oct 11, 2026 •

Copy link
Copy Markdown
Author

Thanks for the suggestion. I'll give it a try, although I still believe this feature would be better suited for DRF itself, like other relational fields such as HyperlinkedRelatedField and SlugRelatedField. I don't think the fact that this feature is being proposed relatively late is, by itself, a compelling reason to keep it out of DRF.

I'll open a PR in drf-extensions and ping you once it's ready.🙂

@HosseinSayyedMousavi

HosseinSayyedMousavi commented Oct 11, 2026 •

Copy link
Copy Markdown
Author

I've been thinking about a broader approach that might be worth discussing separately.

Instead of introducing a field for one specific use case, what if DRF provided a general field that allows the read and write representations to be configured independently?

For example, following the use case in my original PR, the read side could represent a related object using its slug, while the write side could accept nested data through a serializer:

category = FlexibleField(
    read=CategorySerializer(),
    write=serializers.SlugRelatedField(
        slug_field="slug",
    ),
)

The goal would be to make this a reusable abstraction for different read/write combinations, rather than a field tied to a single use case.

@auvipy @merwok @browniebroke — I'd be interested in your thoughts on whether this broader approach could be worth discussing for DRF itself, or whether you think it would still be better suited to a third-party package.

@sayyedmousavi-seedsoft

sayyedmousavi-seedsoft commented Oct 13, 2026 •

Copy link
Copy Markdown

ِDear @auvipy.
Following your suggestion, I've opened a PR in drf-extensions:

[Add FlexibleField and SerializedRelatedField]

I've also explored a more general approach with FlexibleField, alongside the specialized SerializedRelatedField. I'd appreciate your thoughts on the implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

6 participants