Проблема со связанными объектами в REST Framework
У меня есть простое приложение django со следующими моделями:
class Product(models.Model):
__metaclass__ = ABCMeta
title = models.CharField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=100, unique=True)
price = models.IntegerField()
is_published = models.BooleanField(default=True)
@abstractmethod
def __str__(self):
pass
@abstractmethod
def get_absolute_url(self):
pass
class SupplyType(models.Model):
title = models.CharField(max_length=10)
slug = models.SlugField(max_length=100, unique=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('supply_type_detail', kwargs={'slug': self.slug})
class Processor(Product):
supply_type = models.ForeignKey(SupplyType, on_delete=models.CASCADE)
cores_amount = models.IntegerField()
threads_amount = models.IntegerField()
technological_process = models.IntegerField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('processor_detail', kwargs={'slug': self.slug})
Для них были написаны соответствующие сериализаторы:
class SupplyTypeSerializer(ModelSerializer):
class Meta:
model = SupplyType
fields = '__all__'
class ProcessorSerializer(ModelSerializer):
class Meta:
model = Processor
fields = '__all__'
depth = 1
Также были написаны соответствующие представления (для примера я приведу только представления о творении):
class ProcessorCreateAPIView(CreateAPIView):
model = Processor
serializer_class = ProcessorSerializer
class SupplyTypeCreateAPIView(CreateAPIView):
model = SupplyType
serializer_class = SupplyTypeSerializer
Когда я пытаюсь добавить "Тип поставки" с помощью POST запроса, он работает успешно.
Однако, когда я пытаюсь добавить процессор следующим образом:
{
"title": "Intel Pentium Gold G6400",
"slug": "intel-pentium-gold-g6400",
"price": 19690,
"is_published" : true,
"cores_amount": 2,
"threads_amount": 4,
"technological_process": 14,
"supply_type": 1
}
Я получаю ошибку:
django.db.utils.IntegrityError: null значение в столбце "supply_type_id" отношения "store_processor" нарушает not-null ограничение ПОДРОБНОСТИ: Ошибочная строка содержит (1, 2, 4, 14, null).
В итоге возникают следующие вопросы: как это исправить и как, в таком случае, добавить процессор с нужным типом поставки через API (все равно через id) или каким-то другим способом?
В результате, когда я делаю GET запрос, я хотел бы получить что-то вроде этого:
{
"title": "Intel Pentium Gold G6400",
"slug": "intel-pentium-gold-g6400",
"price": 19690,
"is_published" : true,
"cores_amount": 2,
"threads_amount": 4,
"technological_process": 14,
"supply_type":
{
"id": 1,
"title": "OEM",
"slug": "oem"
}
And yeah, sorry for my english.
Вам необходимо использовать концепцию вложенных сериализаторов. Смотрите следующий код
class ProcessorSerializer(ModelSerializer):
supply_type = SupplyTypeSerializer()
class Meta:
model = Processor
fields = '__all__'
В результате, когда вы выполняете GET-запрос, вы получаете что-то вроде этого:
{
"title": "Intel Pentium Gold G6400",
"slug": "intel-pentium-gold-g6400",
"price": 19690,
"is_published" : true,
"cores_amount": 2,
"threads_amount": 4,
"technological_process": 14,
"supply_type": {
"id": 1,
"title": "OEM",
"slug": "oem"
}
}
Для создания процессора вам нужно передать объект supply_type dict, подобный тому, что вы получите в выводе. Но поскольку вы хотите передать вместо этого идентификатор supply_type, вы можете переопределить метод to_internal_value следующим образом и установить поле supply_type как read_only:
def to_internal_value(self, data):
supply_type_id = data.get('supply_type')
internal_data = super().to_internal_value(data)
try:
supply_type = SupplyType.objects.get(id=supply_type_id)
except SupplyType.DoesNotExist:
raise serializers.ValidationError(
{'supply_type': ['Item does not exist']},
)
internal_data['supply_type'] = supply_type
return internal_data
Теперь вы можете создать процессор следующим образом:
{
"title": "Intel Pentium Gold G6400",
"slug": "intel-pentium-gold-g6400",
"price": 19690,
"is_published" : true,
"cores_amount": 2,
"threads_amount": 4,
"technological_process": 14,
"supply_type": 1
}
Окончательный код:
class ProcessorSerializer(serializers.ModelSerializer):
supply_type = SupplyTypeSerializer(read_only=True)
class Meta:
model = Processor
fields = '__all__'
def to_internal_value(self, data):
supply_type_id = data.get('supply_type')
internal_data = super().to_internal_value(data)
try:
supply_type = SupplyType.objects.get(id=supply_type_id)
except SupplyType.DoesNotExist:
raise serializers.ValidationError(
{'supply_type': ['Item does not exist']},
)
internal_data['supply_type'] = supply_type
return internal_data