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

Not able to deserialize OneToOneField relationships in DRF>=3.7.0 #27

Closed
c-oreills opened this issue Jan 17, 2019 · 3 comments
Closed

Comments

@c-oreills
Copy link

Hi Ian,

I've run into an issue when upgrading DRF to v3.7.7 due to our use of expandable_fields

If I have the following code:

class Parent(models.Model):
    pass

class Child(models.Model):
    parent = models.OneToOneField(Parent)

class ChildSerializer(SerializerExtensionsMixin, ModelSerializer):
    class Meta:
        model = Child
        fields = ('id',)

class ParentSerializer(SerializerExtensionsMixin, ModelSerializer):
    class Meta:
        model = Parent
        fields = ('id',)
        expandable_fields = dict(
            child=dict(
                serializer=ChildSerializer,
                id_source='child.id'
            ))

Then this test will fail:

class TestModels(TestCase):
    def test(self):
        parent = Parent.objects.create()

        ParentSerializer(parent).data

with:

Traceback (most recent call last):
  File "/home/christy/projects/dsetest/dseapp/tests.py", line 13, in test
    ParentSerializer(parent).data
  File "/home/christy/.virtualenvs/dsetest/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 537, in data
    ret = super(Serializer, self).data
  File "/home/christy/.virtualenvs/dsetest/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 262, in data
    self._data = self.to_representation(self.instance)
  File "/home/christy/.virtualenvs/dsetest/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 491, in to_representation
    attribute = field.get_attribute(instance)
  File "/home/christy/.virtualenvs/dsetest/local/lib/python2.7/site-packages/rest_framework/relations.py", line 177, in get_attribute
    return get_attribute(instance, self.source_attrs)
  File "/home/christy/.virtualenvs/dsetest/local/lib/python2.7/site-packages/rest_framework/fields.py", line 100, in get_attribute
    instance = getattr(instance, attr)
AttributeError: 'NoneType' object has no attribute 'child'

If I create a Child model and link it to parent, the test passes.

Note that this works in DRF<=3.6.4

I believe this to be due to this commit, which has been linked to this issue and this PR.

We can work around this at other points in our codebase by specifying default=None in serializer fields, however this isn't supported in serializer extensions.

I've created a repo with a POC here (requirements file has necessary library versions).

I'd appreciate any input on how this could be resolved - one option would be remove from expandable_fields and make this a first class field on the serializer but that would require finding all clients which request the expandable field and changing them to no longer ask for it.

Thanks very much in advance!

@evenicoulddoit
Copy link
Owner

Hey! Sorry been out of the loop for a long time but plan on looking into these issues over the next few weeks. Did you solve the problem in the end?

@c-oreills
Copy link
Author

c-oreills commented Apr 19, 2019 via email

@evenicoulddoit
Copy link
Owner

OK @c-oreills I've just had a chance to look at this. Thanks for the detailed description, and the minimal repo to reproduce. I forked the repo and had a play.

You're right, it does have to do with this issue reported against DRF, essentially they made a change which didn't allow for relational fields to be unmatched. Now, this isn't actually an issue with serializer extensions, simply that by using extensions you always get an ID field serialized by default. I made a serializer within the repo to mimic the extensions behaviour:

class VanillaParentSerializer(ModelSerializer):
    child_id = PrimaryKeyRelatedField(
        source='child.id',
        queryset=Child.objects.all(),
        allow_null=True,
    )

    class Meta:
        model = Parent
        fields = ('id','child_id')

Which produces exactly the same error with the DRF version you included in the repo.

However, this issue has since been rectified in DRF (confirmed by bumping the version in the POC repo and re-running), and so I'd consider this now a non-issue. Let me know if otherwise. Thanks!

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

No branches or pull requests

2 participants