Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple fields with the same source clobber each other #4634

Closed
5 of 6 tasks
sbunchridecell opened this issue Oct 29, 2016 · 5 comments
Closed
5 of 6 tasks

Multiple fields with the same source clobber each other #4634

sbunchridecell opened this issue Oct 29, 2016 · 5 comments
Labels
Milestone

Comments

@sbunchridecell
Copy link

sbunchridecell commented Oct 29, 2016

Hey guys, I'm getting weird behavior with many related fields. Is this an error?

Checklist

  • I have verified that that issue exists against the master branch of Django REST framework.
  • I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
  • This is not a usage question. (Those should be directed to the discussion group instead.)
  • This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
  • I have reduced the issue to the simplest possible case.
  • I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)

Steps to reproduce

Create a model serializer where one field renders the relation, and the other field writes to it.

class UserSerializer(serializers.ModelSerializer):
    dogs = DogSerializer(many=True, read_only=True)
    dog_ids = serializers.PrimaryKeyRelatedField(source='dogs', many=True, queryset=Dog.objects.all())

    class Meta:
        fields = ('dogs', 'dog_ids',)
        model = User

Then do a patch.

PATCH /api/users/23 HTTP/1.1
Content-Type: application/json

{
    "dog_ids": [5, 9]
}

Expected behavior

It should update my model.

Actual behavior

It throws an error complaining that nested writes aren't allowed.

AssertionError at /api/users/23
The `.update()` method does not support writable nestedfields by default.
Write an explicit `.update()` method for serializer `app.serializers.DogSerializer`, or set `read_only=True` on nested serializer fields.

tl;dr

This assertion gets called, but it checks all fields rather than just the writable ones:
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/serializers.py#L721

def raise_errors_on_nested_writes(method_name, serializer, validated_data):
    assert not any(
        isinstance(field, BaseSerializer) and
        (key in validated_data) and
        isinstance(validated_data[key], (list, dict))
        for key, field in serializer.fields.items()
    ), (
        'The `.{method_name}()` method does not support writable nested'
        'fields by default.\nWrite an explicit `.{method_name}()` method for '
        'serializer `{module}.{class_name}`, or set `read_only=True` on '
        'nested serializer fields.'.format(
            method_name=method_name,
            module=serializer.__class__.__module__,
            class_name=serializer.__class__.__name__
        )
    )
@aswinm
Copy link

aswinm commented Oct 31, 2016

Passing a list of ids to a PrimaryKeyRelatedField? Can you post what you are trying to achieve here?

@sbunchridecell
Copy link
Author

sbunchridecell commented Oct 31, 2016

Hey @aswinm, basically I want to be able to:

  1. serialize a many-to-many field as nested objects
  2. modify a many-to-many field by passing an array of ids to a "meta" field, in this case dog_ids
  3. use the same field name as the django model in the serialization of the nested objects, in this case dogs

FYI, the following code works and accomplishes 1 and 2, but not 3.

class UserSerializer(serializers.ModelSerializer):
    dog_objects = DogSerializer(source='dogs', many=True, read_only=True)
    dog_ids = serializers.PrimaryKeyRelatedField(source='dogs', many=True, queryset=Dog.objects.all())

    class Meta:
        fields = ('dog_objects', 'dog_ids',)
        model = User

@simone6021
Copy link

simone6021 commented Nov 4, 2016

I can confirm the issue, the pull request that changed the behaviour of nested write check is this #4568 and in my humble opionion i would go for the extra 'read_only' check proposed by @educolo otherwise the issue will happen one way or another.

@pySilver
Copy link

pySilver commented Nov 6, 2016

Having same exact problem.

@sbunchridecell
Copy link
Author

sbunchridecell commented Nov 10, 2016

Awesome, thanks so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants