Daniyal
Daniyal

Reputation: 87

Django rest framework Serializer Save() problem

Hi there i am new ot django and django rest framework and i am having torouble when using serializers with PrimarayKeyTelatedFields() the code below is my code for my models.py

from django.db import models
class Author(models.Model):
    name = models.CharField(max_length=50)
    age = models.IntegerField(default=0)


class Book(models.Model):
    name = models.CharField(max_length=40)
    author = models.ForeignKey(to=Author, on_delete=models.CASCADE)

below is my serializer code from rest_framework import serializers

from books.models import Book, Author
class BookSerializer(serializers.ModelSerializer):
    author_id = serializers.PrimaryKeyRelatedField(many=False,
                                                   queryset=Author.objects.all())

    class Meta:
        model = Book
        fields = ['id', 'name', 'author_id']


class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = ['id', 'name', 'age']

and when i try to execute following commands in shell

>>from books.api.serializers import BookSerializer, AuthorSerializer
>> play1 = BookSerializer(data = { 'author_id':1 ,'name':'book1' })
>>play1.is_valid()
True
>>play1.save()

After executing above i got the huge error as i pasted below

Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 1988, in get_prep_value
    return int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'Author'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\rest_framework\serializers.py", line 962, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\query.py", line 514, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 806, in save
    self.save_base(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 857, in save_base
    updated = self._save_table(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 1000, in _save_table
    results = self._do_insert(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 1041, in _do_insert
    return manager._insert(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\query.py", line 1434, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1620, in execute_sql
    for sql, params in self.as_sql():
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1547, in as_sql
    value_rows = [
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1548, in <listcomp>
    [
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1549, in <listcomp>
    self.prepare_value(field, self.pre_save_val(field, obj))
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1487, in prepare_value
    value = field.get_db_prep_save(value, connection=self.connection)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\related.py", line 1126, in get_db_prep_save
    return self.target_field.get_db_prep_save(value, connection=connection)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 910, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 2668, in get_db_prep_value
    value = self.get_prep_value(value)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 1990, in get_prep_value
    raise e.__class__(
TypeError: Field 'id' expected a number but got <Author: Author object (1)>.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\rest_framework\serializers.py", line 212, in save
    self.instance = self.create(validated_data)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\rest_framework\serializers.py", line 981, in create
    raise TypeError(msg)
TypeError: Got a `TypeError` when calling `Book.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Book.objects.create()`. You may need to make the field read-only, or override the BookSerializer.create() method to handle this correctly.
Original exception was:
 Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 1988, in get_prep_value
    return int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'Author'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\rest_framework\serializers.py", line 962, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\query.py", line 514, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 806, in save
    self.save_base(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 857, in save_base
    updated = self._save_table(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 1000, in _save_table
    results = self._do_insert(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\base.py", line 1041, in _do_insert
    return manager._insert(
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\query.py", line 1434, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1620, in execute_sql
    for sql, params in self.as_sql():
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1547, in as_sql
    value_rows = [
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1548, in <listcomp>
    [
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1549, in <listcomp>
    self.prepare_value(field, self.pre_save_val(field, obj))
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\sql\compiler.py", line 1487, in prepare_value
    value = field.get_db_prep_save(value, connection=self.connection)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\related.py", line 1126, in get_db_prep_save
    return self.target_field.get_db_prep_save(value, connection=connection)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 910, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 2668, in get_db_prep_value
    value = self.get_prep_value(value)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\site-packages\django\db\models\fields\__init__.py", line 1990, in get_prep_value
    raise e.__class__(
TypeError: Field 'id' expected a number but got <Author: Author object (1)>.

Upvotes: 0

Views: 1685

Answers (2)

annonymous
annonymous

Reputation: 816

Cause

The problem is caused by setting author_id with serializer.PrimaryKeyRelatedField

Explanation

Django will internally auto-create an attribute for related fields (ForeignKey, OneToOneField, ...) with the suffix _id appending to the declared field name. The data type of this field is a number. In this case, the author field in Book will have an attribute called author_id. The problem comes from serializer.PrimaryKeyRelatedField returning a model instance in the serializer's validated data, causing field author_id to be set with Author instance. Resulting in an error.

Solution

Rename author_id attribute to author.

class BookSerializer(serializers.ModelSerializer):
    author = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all())

    class Meta:
        model = Book
        fields = ['id', 'name', 'author']

Upvotes: 1

Vivek Kumar
Vivek Kumar

Reputation: 80

you passed here an object instead of id..

 author_id = serializers.PrimaryKeyRelatedField(many=False,
                                               queryset=Author.objects.all())

you should pass an id like this

 author_id = serializers.PrimaryKeyRelatedField(many=False,
                                               queryset=Author.objects.get(id=request.user.id))

Remember whatever you queried it should be an int value not str or object

Upvotes: 2

Related Questions