Search code examples
djangodjango-rest-frameworkdjango-serializer

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


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.


Solution

  • 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)