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

Update nested related OneToOneField without providing its pk #157

Open
JocelynDelalande opened this issue Jan 13, 2022 · 0 comments
Open

Comments

@JocelynDelalande
Copy link

Here is minimal fictive example to explain:

class ChildModel(models.Model):
    name = models.CharField()

class ParentModel(models.Model):
    child = models.OneToOneField(ChildModel, on_delete=models.CASCADE)

class ParentSerializer(WritableNestedModelSerializer):
    class Meta:
        fields = ['child']
        model = ParentModel

class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ['name']
        model = ChildModel

child = ChildModel.objects.create(name='fu')
parent = ParentModel.objects.create(child=child)

old_child_pk = child.pk
parent_serializer = ParentSerializer(data={'pk': parent.pk, 'child': {'name': 'bar'}})
parent_serializer.is_valid(raise_exception=True)
parent = parent_serializer.save()

# What I'd like:
# Child serializer went through update()

assert parent.child.pk == old_child_pk
assert ChildModel.objects.count() == 1

# What I get:
# Child serializer went through create()

assert parent.child.pk != old_child_pk
assert ChildModel.objects.count() == 2  # I got one orphaned

What is the recommended way to achieve what I want ?

I believe this behavior is expectable as long as you have a composition relation, which can also be the case with ForeignKey. In other words, my behavior may be expected when ChildModel has no independent existence from ParentModel.

For esthetic/practical reason I do not want to provide the pk of child model (can be inferred by code).

Current workaround I found is overriding ParentModel ; but this is unclean.

    # Override of private method, uh-oh
    def _get_related_pk(self, data, model_class):
        if model_class == ChildModel and self.instance and self.instance.child:
            # Reuse existing related instance instead of recreating one on each update
            return self.instance.child.pk
        else:
            return super()._get_related_pk(data, model_class)

Any thoughts ? I'm wondering if the library could not offer a way to do that.

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

1 participant