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

Foreign keys with on_delete=SET_NULL should not be deleted on update IMHO #72

Closed
izimobil opened this issue Jan 31, 2019 · 2 comments
Closed

Comments

@izimobil
Copy link
Contributor

Hi,

I have the following models (simplified for clarity):

class User(models.Model):
    first_name = models.CharField(
        'First name',
        max_length=150,
    )
    last_name = models.CharField(
        'Last name',
        max_length=150,
    )


class Badge(models.Model):
    number = models.BigIntegerField(
        'Number',
        primary_key=True,
        unique=True
    )
    user = models.ForeignKey(
        User,
        models.SET_NULL,
        verbose_name="Owner",
        related_name='badges',
        blank=True,
        null=True
    )

And the following serializers:

class UserBadgeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Badge
        fields = ('number',)


class UserSerializer(WritableNestedModelSerializer):
    badges = UserBadgeSerializer(many=True, required=False)

    class Meta:
        model = User
        fields = (
            'pk', 'first_name', 'last_name', 'badges'
        )

As you can see a "Badge" can live without a user (hence the SET_NULL on the foreign key).
When I do the following request:


POST /api/users {
    "first_name": "Foo",
    "last_name": "Bar",
    "badges": [{"number": 1234}, {"number": 1235}]
}

All is fine, the user and badges are created and associated.
However, when I update the user to remove one of its badges:


PUT /api/users/1/ {
    "first_name": "Foo",
    "last_name": "Bar",
    "badges": [{"number": 1234}]
}

The badge 1235 is removed from the user (which is fine) but also gets deleted from the db.

I think (but I might be wrong) the correct behavior for foreign keys with on_delete != CASCADE, would be to only update the foreignkey and set it to None.

I have a working patch for this, if you're interested I can submit a pull request.

In short, in NestedUpdateMixin.delete_reverse_relations_if_need():

                    qs = model_class.objects.filter(pk__in=pks_to_delete)
                    if related_field.remote_field.on_delete == CASCADE:
                        qs.delete()
                    else:
                        qs.update(**{related_field.name: None})

Regards.

izimobil added a commit to izimobil/drf-writable-nested that referenced this issue Feb 1, 2019
…te=SET_DEFAULT

This fixes issue beda-software#72, see the issue description for more details.
@ruscoder
Copy link
Member

ruscoder commented Feb 4, 2019

Hello @izimobil! Thank you for your contribution. I agree with you, that we shouldn't delete related instances when they have null=True.

I'll try to review your PR.

@ruscoder
Copy link
Member

Available in 0.7.0

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