floflo29
floflo29

Reputation: 2321

Serialize a Django model with a ForeignKey

In Django Rest Framework, I have a simple Present model which consists in the following fields:

class Present(models.Model):
    name = models.CharField(max_length=15)
    price = models.FloatField()
    link = models.CharField(max_length=15)
    isAlreadyBought = models.BooleanField()
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)

The serializers for the User and Present models are these ones:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'password', 'email')



class PresentSerializer(serializers.ModelSerializer):

    user_id = serializers.RelatedField(source='User', read_only=True)

    class Meta:
        model = Present
        fields = ('name', 'link', 'price', 'isAlreadyBought', 'user_id')


    def create(self, validated_data, **kwargs):
        print(kwargs)
        print(validated_data)
        return Present.objects.create(**validated_data)

My goal is, from the following POST request to save a new Present. To do so, I've added a user_id field to my request to link my Present with a given User:

import requests

save_present = {'name': 'figurine', 'price': '50.8', 'link': 'fake_link', 'isAlreadyBought': 'True', 'user_id': '22'}
r = requests.post('http://127.0.0.1:8000/present_list', json=save_present)

Here is how I am trying, without success so far, to save my Present:

class PresentList(APIView):
# add a new present
def post(self, request, format=None):

    # get user id:
    # print(request.data['user_id'])
    #
    # user = User.objects.get(id=request.data['user_id'])

    machin = request.data
    # machin.pop('user_id', None)
    # machin['user'] = UserSerializer(user).data

    print('Machin', machin)

    serializer = PresentSerializer(data=machin)

    if serializer.is_valid():
        print('SERIALIZER OK')
        serializer.save()

    else:
        print(serializer.errors())


    return Response('')

I do not manage to find out the best Django-based way to achieve this, as I get this error:

   November 20, 2016 - 19:55:34
Django version 1.10.3, using settings 'tutorial.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
23
Machin {'name': 'figurine', 'link': 'fake_link', 'isAlreadyBought': 'True', 'price': '50.8', 'user': {'password': 'PASSWORD', 'email': '[email protected]', 'username': 'Florian'}}
SERIALIZER OK
Internal Server Error: /present_list
Traceback (most recent call last):
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 337, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: blog_present.user_id

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

Traceback (most recent call last):
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/rest_framework/views.py", line 477, in dispatch
    response = self.handle_exception(exc)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/rest_framework/views.py", line 437, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/rest_framework/views.py", line 474, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/Florian/PycharmProjects/Backend/tutorial/blog/views.py", line 54, in post
    serializer.save()
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/rest_framework/serializers.py", line 214, in save
    self.instance = self.create(validated_data)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/rest_framework/serializers.py", line 902, in create
    instance = ModelClass.objects.create(**validated_data)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/query.py", line 399, in create
    obj.save(force_insert=True, using=self.db)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/base.py", line 796, in save
    force_update=force_update, update_fields=update_fields)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/base.py", line 824, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/base.py", line 908, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/base.py", line 947, in _do_insert
    using=using, raw=raw)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/query.py", line 1045, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 1054, in execute_sql
    cursor.execute(sql, params)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/Florian/anaconda/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 337, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: blog_present.user_id
[20/Nov/2016 19:55:36] "POST /present_list HTTP/1.1" 500 17246

EDIT:

The only way to save my Present is to add blank=True or/and null=True to my ForeignKey. However, I would like to assign the user_id field while saving my object but this field is not kept in the validated_data. How can I solve this?

Upvotes: 0

Views: 1422

Answers (1)

martinarroyo
martinarroyo

Reputation: 9701

You are setting the serializer field to read_only, which means it will not be used when creating or updating an object, only when reading it.

Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored. Set this to True to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.

http://www.django-rest-framework.org/api-guide/fields/#read_only

Also, try using PrimaryKeyRelatedField instead of RelatedField. See the documentation for the field.

Upvotes: 1

Related Questions