Home > Enterprise >  How to manually change value of primary key in Django Model through serializers?
How to manually change value of primary key in Django Model through serializers?

Time:07-02

Is it somehow possible to manually change ID value in AutoField (primary key) through serializer?
I found this in documentation of Django: https://docs.djangoproject.com/en/4.0/ref/models/instances/#auto-incrementing-primary-keys, but I have no idea how to do this including serializers.

My task is: If post with given ID does not exists, fetch post from external API and save it.

Model:

from django.db import models

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    user_id = models.IntegerField(default=1)
    title = models.CharField(max_length=200)
    body = models.CharField(max_length=500)

My serializer:

from rest_framework import serializers
from .models import Post


class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'user_id', 'title', 'body']

My view:

@api_view(['GET', 'PUT', 'DELETE'])
def post_detail_id(request, id):
    try:
        post = Post.objects.get(pk=id)
    except Post.DoesNotExist:
        #-----------------------------------------------------------#
        found_post = search_post(id) #fetch post from external API
        if request.method == "GET" and found_post is not None:
            serializer = PostSerializer(data=found_post)
            if serializer.is_valid():
                serializer.save()
                return Response(status=status.HTTP_201_CREATED)
        #-----------------------------------------------------------#
        return Response(status=status.HTTP_404_NOT_FOUND)
    return post_detail(request, "id", post) #method to handle CRUD

Post structure:

 {
    "user_id": 1,
    "id": 1,
    "title": "Blabla",
    "body": "Lorem Ipsum"
  },

This implementation fetch post with given ID from API, then saves it, but with different ID. Are there any better ways to do this? Let me know below!

CodePudding user response:

have you tried PostSerializer(data=found_post, id = id)?

CodePudding user response:

The AutoField function to build a pk requires a unique identifier and it cannot/should not be changed in the DB (as far as I am aware).

I would focus on accomplishing the use-case another way. You could use try/except to check if the object exists:

try:
    ObjectName.objects.get(id=self.kwargs['id'])  # insert correct syntax for your use case
except ObjectName.DoesNotExist:
    # Make external call here

CodePudding user response:

at first: You are dont need to create autokey. Django do it automatically.

class Post(models.Model):
    user_id = models.IntegerField(default=1)
    title = models.CharField(max_length=200)
    body = models.CharField(max_length=500)

at second: You are save model on GET, it's bad desigion:

  • GET for read.
  • POST for write.

At last, try to use view and viewsets from DRF, it is easier:

class CreatePostAPIView(CreatePostAPIView):
    model=Post

You can call this DRF-view everythere:

def post_detail_id(request, id):
    ....    
    except Post.DoesNotExist:
            #-----------------------------------------------------------#
            request.data = request.method == "GET" and search_post(id) #fetch 
            if request.data:
                return CreatePostAPIView().post(request, *args, **kwargs)
            #-----------------------------------------------------------#
            return Response(status=status.HTTP_404_NOT_FOUND)

My opinion, somewhere business-logic in post_detail_id is broken.

  • Related