Можно ли вручную изменить значение ID первичного ключа в Django Model через сериализаторы?
Можно ли как-то вручную изменить значение ID в AutoField (первичный ключ) через сериализатор?
Я нашел это в документации Django: https://docs.djangoproject.com/en/4.0/ref/models/instances/#auto-incrementing-primary-keys, но я понятия не имею, как это сделать, включая сериализаторы.
Моя задача такова: Если пост с заданным ID не существует, получить пост из внешнего API и сохранить его.
Модель:
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)
Мой сериализатор:
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'user_id', 'title', 'body']
Мое мнение:
@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
Структура должности:
{
"user_id": 1,
"id": 1,
"title": "Blabla",
"body": "Lorem Ipsum"
},
Эта реализация получает пост с заданным ID из API, затем сохраняет его, но уже с другим ID. Есть ли лучшие способы сделать это? Дайте мне знать ниже!
пробовали ли вы PostSerializer(data=found_post, id = id)
?
Функция AutoField для построения пк требует уникальный идентификатор, и он не может/не должен быть изменен в БД (насколько я знаю).
Я бы сосредоточился на том, чтобы решить эту задачу другим способом. Вы можете использовать try/except для проверки существования объекта:
try:
ObjectName.objects.get(id=self.kwargs['id']) # insert correct syntax for your use case
except ObjectName.DoesNotExist:
# Make external call here
сначала: Вам не нужно создавать автоключ. Django сделает это автоматически.
class Post(models.Model):
user_id = models.IntegerField(default=1)
title = models.CharField(max_length=200)
body = models.CharField(max_length=500)
во второй: Вы сохраняете модель на GET, это плохая десигнация:
- GET для чтения.
- POST для записи.
Наконец, попробуйте использовать представления и наборы представлений из DRF, это проще:
class CreatePostAPIView(CreatePostAPIView):
model=Post
Вы можете вызывать это DRF-представление везде:
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)
Мое мнение, где-то нарушена бизнес-логика в post_detail_id.
Если вы используете serializers.ModelSerializer
, как в приведенном выше примере class CarSerializer(serializers.ModelSerializer):
. Вы можете установить дополнительные свойства при сохранении.
serializer = CarSerializer(data=car)
if serializer.is_valid():
serializer.save(id=id)
Вы можете добавлять другие свойства, если они есть в модели. Я не могу найти другого решения, чтобы сделать это.
Я нашел этот способ здесь Solution. Надеюсь, это поможет