Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

View pre_save called before model clean #729

Closed
joaomsa opened this Issue · 7 comments

4 participants

@joaomsa

In my model I test some constraints that rely on field that's added by the ListCreateAPIView's pre_save method, however since the models's clean method is called before it, I get a DoesNotExist exception when I try to access self.owner. Is this the indented order?

class Car(models.Model):
    owner = models.ForeignKey('auth.User', related_name='cars')
    ...

    def clean(self, *args, **kwargs):
        super(Car, self).clean(*args, **kwargs)

        print('called clean')
        querySet = self.__class__._default_manager.filter(owner=self.owner)
    ...
class CarList(generics.ListCreateAPIView):
    ...
    def pre_save(self, obj):
        print('called pre_save')
        obj.owner = self.request.user
@tomchristie
Owner

Can see the issue yup, but I'm not sure what'd be a good we to resolve it.
At the moment the object isn't available on the serializer until after .is_valid() has been called, so you can't call pre_save until after that's happened.

@ameyc

Was this ever resolved?

@tomchristie
Owner

@asc89 Nope. It might be useful to have someone rephrase the problem they are seeing - this ticket always confuses me a little.

@ameyc

I'm running into something very similar to this ticket. In our Django model's clean() method we're accessing a field (owner)that is being set in the pre_save() method of the ModelViewSet. This leads to a DoesNotExist exception in the clean(). Is there any other hook (other than overriding the create(), where I could be setting the owner by pulling it from the request so that it is there when clean() gets called?

@bartvandendriessche

I worked around this problem by overriding restore_fields and restore_object in my ModelSerializer subclass.

If you have an owner model in the request, you'd do something like this:

class OwnedModelSerializer(serializers.ModelSerializer):
    def restore_fields(self, data, files):
        owner = self.context['request'].owner

        if data and not 'owner' in data:
            """
            Make sure owner is available in data, in case the owner attribute is NOT an excluded field.
            """
            d = data.copy()
            d['owner'] = owner.pk
            data = d

        reverted_data = super(OwnedModelSerializer, self).restore_fields(data, files)

        if not 'owner' in reverted_data:
            """
            Owner field is excluded, and thus ignored by restore_fields.
            Let's force it to be present anyway.
            """
            reverted_data['owner'] = owner

        return reverted_data

    def restore_object(self, attrs, instance=None):
        """
        The attrs parameter is basically the reverted_data returned by restore_fields.
        """
        ret = super(OwnedModelSerializer, self).restore_object(attrs, instance)

        if ret == attrs:  # I think this is true in case of errors, not sure
            return attrs

        ret.owner = attrs['owner']

        return ret
@tomchristie tomchristie added this to the 3.0 Release milestone
@tomchristie
Owner

Hoping the 3.0 redesign will help resolve this, as the serializer changes will also affect the default pre_save implementation.

@tomchristie
Owner

Closing pending 3.0 - feel free to reopen if it does not resolve the issue.
Also marking this with the Serializer to ensure it gets a further review prior to release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.