The `.create()` method does not support writable dotted-source fields by default. Write an explicit `.create()` method for serializer

Viewed 3493

I am trying to enable post methods in my borrowedview to enable admins, select from current users, and also select from the available books.

serializers.py
class BookListSerializer(serializers.ModelSerializer):
    authors = serializers.SlugRelatedField(many = True, queryset = models.Author.objects.all(),slug_field = 'name',) #To represent the relationship as a string instead of id
    genre = serializers.SlugRelatedField(many = True,queryset = models.Genre.objects.all(),slug_field = 'name')


class Meta:
    model = models.Book
    fields = ('name','authors','rating', 'genre')

class BorrowedSerializer(serializers.ModelSerializer):
    who_borrowed = serializers.PrimaryKeyRelatedField(queryset = get_user_model().objects.all() ,source = 'who_borrowed.username',)
name = serializers.PrimaryKeyRelatedField(queryset = models.Book.objects.all(),
                                         source = 'name.name',)

#borrowed_date = serializers.DateTimeField(format = "%H:%M, %d-%m-%Y")
#returned_date = serializers.DateTimeField(format = "%H:%M, %d-%m-%Y" )

class Meta:
    model = models.Borrowed
    fields = ('who_borrowed','name','has_returned','borrowed_date','returned_date',)

Then my models

models.py

class Book(models.Model):
name = models.CharField(max_length = 150,)   #Name of books
authors = models.ManyToManyField(Author,)     
genre = models.ManyToManyField(Genre)       
publisher = models.ForeignKey(Publisher, on_delete = models.SET_DEFAULT, default = '2') 
#A book should have a publisher will include a none field for books without publishers

pub_date = models.DateField()
price = models.DecimalField(max_digits = 10, decimal_places = 2) 
isbn = models.CharField(max_length = 13, unique = True, null = True, blank = True,
                        validators = [MinLengthValidator(13)]) 


class Borrowed(models.Model):    #Model for users borrowing and returning
name = models.ForeignKey(Book, on_delete = models.CASCADE,) #Consider making one to many field
borrowed_date = models.DateTimeField(auto_now_add = True, )   #Date is created as soon as instance is created
has_returned = models.BooleanField(default = False)    #Field that determines if a model is returend or not
returned_date = models.DateTimeField(null = True, blank = True,)    #Date that changes as soon as book is returned
who_borrowed = models.ForeignKey(get_user_model(), on_delete = models.SET_DEFAULT, default ='9c495b90-3900-43d1-875d-6b15d5d5ab55')

The Django browseable api shows the books to choose from and the user borrowing the book just as I want but when I want to post the request it shows the error from the title. I don't know how to make a create method that would allow those options to show and would allow the post or put requests.

In a nutshell if I remove the source argument everything works fine, but I want the data shown not to be the Id or the UUID but the usernames and the names of the books instead.

3 Answers

You can refer DRF- doc.

Following changes should be enough in your case.

class BorrowedSerializer(serializers.ModelSerializer):
    who_borrowed = serializers.PrimaryKeyRelatedField(queryset = get_user_model().objects.all() ,source = 'who_borrowed.username',)
    name = serializers.PrimaryKeyRelatedField(queryset = models.Book.objects.all(),
                                         source = 'name.name',)

    class Meta:
        model = models.Borrowed
        fields = ('who_borrowed','name','has_returned','borrowed_date','returned_date',)

    def create(self, validated_data):
        return models.Borrowed.objects.create(**validated_data)
        # or 
        # return super(BorrowedSerializer, self).create(validated_data)
class BorrowedSerializer(serializers.ModelSerializer):
who_borrowed = serializers.SlugRelatedField(queryset = get_user_model().objects.all(),slug_field = 'username')
name = serializers.SlugRelatedField(queryset = models.Book.objects.all(), slug_field = 'name')

Changing the "PrimaryKeyRelatedFields" to "SlugRelatedFields" also worked for me.

The message of the error the create method doesn't support writable dotted source fields by default is refering to name.name in the source argument of the customized serializer field,

so other ways to solve this are :

1. add a readonly=True in your new field

2. delete the customized field, so you get back to the id instead of the name.

Related