Невозможно передать экземпляр при создании записи в БД в django
У меня есть две модели, DocumentData & RecurringInvoice, которые имеют отношения один к одному друг с другом. Когда я создаю запись в таблице RecurringInvoice, я хочу передать экземпляр DocumentData вместо id. Но я получаю ошибку, говорящую:
{'document_data': [ErrorDetail(string='Incorrect type. Expected pk value, received DocumentData.', code='incorrect_type')]}
Работает, если я передаю id экземпляра. Насколько я знаю, для связи записей можно передавать либо экземпляр, либо id. Так почему же он не работает, когда я передаю экземпляр?
Соответствующий код контроллера:
try:
# get the document data instance
doc_data = DocumentData.objects.get(id=docDataID)
except DocumentData.DoesNotExist:
return Response({
"message": "Document data does not exist"
}, status=status.HTTP_400_BAD_REQUEST)
invoice_serializer = RecurringInvoiceSerializer(
data={
"document_data": doc_data,
"send_date": request.data["send_date"],
"recipients": request.data["recipients"],
"invoice_name": request.data["invoice_name"]
}
)
if not invoice_serializer.is_valid():
print(invoice_serializer.errors, invoice_serializer._errors)
return Response({"message": "Failed to save invoice data"}, status=status.HTTP_400_BAD_REQUEST)
invoice_serializer.save()
Модель RecurringInvoice:
class RecurringInvoice(models.Model):
document_data = models.OneToOneField(
DocumentData, on_delete=models.CASCADE, null=True, blank=True)
send_date = models.IntegerField(
default=1,
validators=[MinValueValidator(1), MaxValueValidator(28)]
)
invoice_name = models.CharField(max_length=255)
recipients = ArrayField(models.CharField(max_length=100))
is_paused = models.BooleanField(default=False)
stop_date = models.DateField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return f"ID: {self.id}, Name: {self.invoice_name}, Active Till: {self.stop_date}"
class Meta:
verbose_name = "Recurring Invoice"
verbose_name_plural = "Recurring Invoices"
Модель документаДанные:
class DocumentData(models.Model):
invoices_sent_count = models.IntegerField(default=0)
service_category = models.CharField(max_length=255, blank=True, null=True)
from_company_name = models.CharField(max_length=255)
from_company_number = models.CharField(
max_length=255, blank=True, null=True
)
from_company_address = models.CharField(
max_length=255, blank=True, null=True
)
Ошибка, с которой вы столкнулись, указывает на то, что сериализатор ожидает значение первичного ключа (pk) экземпляра DocumentData
, а не сам экземпляр. Это связано с тем, что сериализаторы Django REST Framework по умолчанию ожидают первичные ключи для отношений при создании или обновлении связанных объектов.
Чтобы передавать экземпляр напрямую вместо первичного ключа, необходимо модифицировать сериализатор, чтобы он принимал и правильно обрабатывал вложенные отношения. Этого можно добиться с помощью вложенных сериализаторов. Вот как можно модифицировать сериализатор:
from rest_framework import serializers
class DocumentDataSerializer(serializers.ModelSerializer):
class Meta:
model = DocumentData
fields = ['id', 'invoices_sent_count', 'service_category', 'from_company_name', 'from_company_number', 'from_company_address']
class RecurringInvoiceSerializer(serializers.ModelSerializer):
document_data = DocumentDataSerializer()
class Meta:
model = RecurringInvoice
fields = ['document_data', 'send_date', 'recipients', 'invoice_name']
def create(self, validated_data):
document_data_data = validated_data.pop('document_data')
document_data = DocumentData.objects.create(**document_data_data)
recurring_invoice = RecurringInvoice.objects.create(document_data=document_data, **validated_data)
return recurring_invoice
Когда вы передаете экземпляр document_data
в RecurringInvoiceSerializer
, он автоматически создает связанный экземпляр DocumentData
. Метод create в сериализаторе переопределяется для обработки вложенного создания связанных объектов.