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

Django REST 3.8.2 CurrentUserDefault doesn't work #6031

Closed
damonsu opened this issue Jun 17, 2018 · 9 comments
Closed

Django REST 3.8.2 CurrentUserDefault doesn't work #6031

damonsu opened this issue Jun 17, 2018 · 9 comments

Comments

@damonsu
Copy link

damonsu commented Jun 17, 2018

When i tried to create a new Post, i get always the following error:
Exception Value: | (1048, "Column 'user_id' cannot be null")

But i get no error before i updated to Django Rest 3.8.2. It seems like that the function CurrentUserDefault doesn't work.

My Code:

class PostSerializer(serializers.ModelSerializer):
user = UserSerializer(
    many = False,
    read_only = True,
    default=serializers.CurrentUserDefault()
)

class Meta:
    model = Post
    fields = ('id', 'user', 'post_date')

def create(self, validated_data):
    return Post.objects.create(**validated_data)

**Solution based on the reply of @blueyed **

def create(self, validated_data):
     if 'user' not in validated_data:
         validated_data['user'] = self.context['request'].user
     return Post.objects.create(**validated_data)
@xordoquy
Copy link
Collaborator

Due to #5886 this will not work any longer.
You now need to override the view and explicitly add the current user.

Somewhat off topic, but it looks like the documentation isn't up to date with this new behavior (http://www.django-rest-framework.org/api-guide/serializers/#specifying-read-only-fields)

Note: There is a special-case where a read-only field is part of a unique_together constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user.

The right way to deal with this is to specify the field explicitly on the serializer, providing both the read_only=True and default=… keyword arguments.

One example of this is a read-only relation to the currently authenticated User which is unique_together with another identifier. In this case you would declare the user field like so:

user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())

@carltongibson
Copy link
Collaborator

carltongibson commented Jun 18, 2018

The example there is still right for validation (where you do need the default due to the unique together constraint).

We need to add a bit more re the need to supply the value when saving.

@anx-ckreuzberger
Copy link
Contributor

Hi!

I'm going to do some shameless self-promotion here (sorry for that), but my package should fix your issue.

For your use-case of setting the current user (automagically), take a look at the Django-UserForeignKey Package.

It works as a Django Middleware and sets the current user in your model, so you don't need to rely on your Devevelopers to always set the current user in your View Logic or serializers.

(I've also created a YouTube Video for a demo).

@blueyed
Copy link
Contributor

blueyed commented Jun 19, 2018

Another approach might be to set it in your serializer's create by default: https://github.com/lock8/django-rest-framework-jwt-refresh-token/pull/35/files#diff-84229b1d4af72d928beddfa32e80cc8eR23 (?)

@carltongibson
Copy link
Collaborator

@blueyed: Yes. Pass the value during perform_create() in the view (which calls save()) — or override save() or create() or update() in the serialiser as appropriate.

Extra notes in the docs emphasising this would be welcome. Where would you (i.e. all of you) expect to see that note? (I don't think it'll need a lot. PRs there welcome.)

@damonsu
Copy link
Author

damonsu commented Jun 19, 2018

@blueyed you code works like a magic!! Thank you!

@damonsu damonsu closed this as completed Jun 19, 2018
@blueyed
Copy link
Contributor

blueyed commented Jun 19, 2018

@damonsu
Great, you're welcome.

@carltongibson
Regarding docs I've stumpled upon this: https://github.com/encode/django-rest-framework/blame/3fcc076d9124fc202be1a4379b6b753209c7afbe/docs/api-guide/generic-views.md#L156
Also read_only is pretty clear about it already: https://github.com/encode/django-rest-framework/blob/3fcc076d9124fc202be1a4379b6b753209c7afbe/docs/api-guide/fields.md#read_only.

Therefore it is likely more an issue when updating to the new behavior, and you have to remember this change (e.g. in the case of https://github.com/lock8/django-rest-framework-jwt-refresh-token I still was bisecting to find the issue, although I came across this before already).

@carltongibson
Copy link
Collaborator

...although I came across this before already

Indeed. 🙂 (IIRC, it was you that dug out the root issue here)

@to-bee
Copy link

to-bee commented Dec 7, 2021

Using serializers.HiddenField in combination with CurrentUserDefault works fine: HiddenField(default=CurrentUserDefault())

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

6 participants