Reputation: 9800
I'm using Django 2.0
and Django REST Framework
to write REST API
.
my settings.py contains settings for DRF
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated'
]
}
and every request must be signed using any of the DEFAULT_AUTHENTICATION_CLASSES
method.
In contacts/serializers.py
class ContactSerializer(serializers.HyperlinkedModelSerializer):
phone_numbers = ContactPhoneNumberSerializer(source='contactphonenumber_set', many=True)
class Meta:
model = Contact
fields = ('url', 'first_name', 'last_name', 'full_name', 'date_of_birth', 'phone_numbers')
def create(self, validated_data):
phone_numbers = validated_data.pop('contactphonenumber_set')
emails = validated_data.pop('contactemail_set')
instance = Contact.objects.create(**validated_data)
for phone_data in phone_numbers:
ContactPhoneNumber.objects.create(contact=instance, **phone_data)
return instance
print(validated_data)
gives following data
{'first_name': 'Anshuman', 'last_name': 'Upadhyay', 'date_of_birth': datetime.date(2018, 5, 15), 'contactphonenumber_set': [], 'user_id': <SimpleLazyObject: <User: anuj>>}
The user_id
is SimpleLazyObject
thus giving error on save
TypeError: int() argument must be a string, a bytes-like object or a number, not 'SimpleLazyObject'
The error is on the line instance = Contact.objects.create(**validated_data)
How can I pass authenticated user to user
field?
Edit 2: contacts/models.py
class Contact(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100, blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
contacts/views.py
class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactSerializer
permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)
def get_queryset(self):
return Contact.objects.filter(user=self.request.user)
def perform_create(self, serializer):
serializer.save(user_id=self.request.user)
Upvotes: 0
Views: 3921
Reputation: 15390
You could use self.context
for this http://www.django-rest-framework.org/api-guide/serializers/#including-extra-context
If you are using GenericAPIView
context is passed automatically
First of all you don't need to pass user_id
to your serializer and then you need to update your ContactSerializer
to look like this.
class ContactSerializer(serializers.HyperlinkedModelSerializer):
phone_numbers = ContactPhoneNumberSerializer(source='contactphonenumber_set', many=True)
class Meta:
model = Contact
fields = ('url', 'first_name', 'last_name', 'full_name', 'date_of_birth', 'phone_numbers')
def create(self, validated_data):
phone_numbers = validated_data.pop('contactphonenumber_set')
emails = validated_data.pop('contactemail_set')
instance = Contact.objects.create(user=self.context['request'].user, **validated_data)
for phone_data in phone_numbers:
ContactPhoneNumber.objects.create(contact=instance, **phone_data)
return instance
You shouldn't overwrite perform_create
class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactSerializer
permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)
def get_queryset(self):
return Contact.objects.filter(user=self.request.user)
Upvotes: 1
Reputation: 88549
Assuming your Contact
model contains an FK relation with AuthUserModel
. So, your instance creation statement must be like this,
user = get some user instance from `validated` data
instance = Contact.objects.create(user=user,**validated_data)
This is the general solution for your question, If you add your Contact
model, we could help you more
UPDATE-1
Change your create()
as below,
def create(self, validated_data):
phone_numbers = validated_data.pop('contactphonenumber_set')
emails = validated_data.pop('contactemail_set')
user = validated_data.pop('user') # change 1
instance = Contact.objects.create(user=user, **validated_data) # # change 2
for phone_data in phone_numbers:
ContactPhoneNumber.objects.create(contact=instance, **phone_data)
return instance
Update-2
You could use user = serializers.CurrentUserDefault()
in serializer as below,
class ContactSerializer(serializers.HyperlinkedModelSerializer):
phone_numbers = ContactPhoneNumberSerializer(source='contactphonenumber_set', many=True)
user = serializers.CurrentUserDefault()
class Meta:
model = Contact
fields = ('url', 'first_name', 'last_name', 'full_name', 'date_of_birth', 'phone_numbers')
def create(self, validated_data):
phone_numbers = validated_data.pop('contactphonenumber_set')
emails = validated_data.pop('contactemail_set')
user = validated_data.pop('user_id')
instance = Contact.objects.create(user=user, **validated_data)
for phone_data in phone_numbers:
ContactPhoneNumber.objects.create(contact=instance, **phone_data)
return instance
CurrentUserDefault()
is do the same job as self.context.get('request').user
Upvotes: 1