Как в DRF сериализовать связанную модель (OneToOne) и отобразить данные не в типе данных списка, а в экземпляре с одним значением?
Ниже приведен код с текущим и ожидаемым результатом. Пожалуйста, помогите, спасибо.
В таблице ProductPriceMapping таблица ProductDetail и PriceList связаны отношением OneToOne, но при получении данных для цены с аргументом related_name= должно быть одно значение для одного товара, но отображаются данные типа List.
##models.py
class PriceList(models.Model):
priceCode = models.BigAutoField(primary_key= True)
maxRetailPrice= models.FloatField(max_length=20)
baseDiscount = models.FloatField(max_length=20, default=0)
seasonalDiscount = models.FloatField(max_length=20, default=0)
def __str__(self):
return '%s'% (self.maxRetailPrice)
class ProductDetail(models.Model):
productCode = models.BigAutoField(primary_key=True)
productName = models.CharField(max_length=100)
manufacturer = models.CharField(max_length=100)
def __str__(self):
return self.productName
class ProductPriceMapping(models.Model):
productPriceCode= models.BigAutoField(primary_key=True)
productCode= models.ForeignKey(ProductDetail,on_delete=models.CASCADE,related_name='price')
priceCode= models.OneToOneField(PriceList,on_delete=models.CASCADE)
def __str__(self):
return '%s' % (self.priceCode)
#serializers.py
from .models import CategoryDetail, EmployeeDetail, ProductCategoryMapping, ProductPriceMapping, SalaryDetail, ProductDetail, PriceList
class ProductPriceListSerializer(serializers.ModelSerializer):
class Meta:
model = PriceList
fields = ('priceCode','maxRetailPrice',
'baseDiscount', 'seasonalDiscount')
class ProductPriceMappingSerializer(serializers.ModelSerializer):
class Meta:
model= ProductPriceMapping
fields= ('productPriceCode','productCode', 'priceCode')
class ProductDetailsSerializer(serializers.ModelSerializer):
category= serializers.StringRelatedField(many= True, read_only= True)
price = serializers.StringRelatedField( many= True, read_only= True)
class Meta:
model = ProductDetail
fields = ('productCode', 'productName', 'manufacturer','category', 'price')
API как выглядит:
[
{
"productCode": 1,
"productName": "NeoChef",
"manufacturer": "LG",
"category": [
"1: Microwave Oven"
],
"price": [
"26000.0" ##expected the price value not be in a list
]
},
{
"productCode": 2,
"productName": "The Frame",
"manufacturer": "Samsung",
"category": [
"2: Television"
],
"price": [
"120000.0" ##expected the price value not be in a list
]
},
{
"productCode": 3,
"productName": "Galaxy S22+",
"manufacturer": "Samsung",
"category": [
"3: Smart Phone"
],
"price": [
"79000.0" ##expected the price value not be in a list
]
}
]
#expected
[
{
"productCode": 1,
"productName": "NeoChef",
"manufacturer": "LG",
"category": [
"1: Microwave Oven"
],
"price": "26000.0"
}
]```
В вашем случае поле price не является связанным один к одному, вам нужно либо изменить productCode на OneToOneField, либо, если вы не хотите менять поле DB, вы можете достичь того же результата просто с помощью SerializerMethodField. В первом случае должно помочь удаление аргумента many=True из поля сериализатора. Во втором случае, SerializerMethodField поможет вам сделать ваше пользовательское представление, например:
class ProductDetailsSerializer(serializers.ModelSerializer):
category= serializers.StringRelatedField(many=True, read_only=True)
price = serializers.SerializerMethodField()
class Meta:
model = ProductDetail
fields = ('productCode', 'productName', 'manufacturer','category', 'price')
def get_price(self, obj):
# If it's guaranteed that there will be only one related object, or retrieve the needed object depending on your demands
return str(obj.price.first())
Одним из простых способов является использование MethodField...
class ProductPriceMappingSerializer(serializers.ModelSerializer):
priceCode = serializers.SerializerMethodField()
class Meta:
model= ProductPriceMapping
fields= ('productPriceCode','productCode', 'priceCode')
@staticmethod
def get_priceCode(obj):
return obj.priceCode.maxRetailPrice # or any other fields that you like to show in your response
но если вы хотите показать все поля priceList на основе вашего другого сериализатора, вы можете сделать что-то вроде:
class ProductPriceMappingSerializer(serializers.ModelSerializer):
priceCode = ProductPriceListSerializer()
class Meta:
model= ProductPriceMapping
fields= ('productPriceCode','productCode', 'priceCode')
Спасибо, ребята, решено
##models.py
class ProductPriceMapping(models.Model):
productPriceCode= models.BigAutoField(primary_key=True)
productCode= models.OneToOneField(ProductDetail,on_delete=models.CASCADE,related_name='price')
priceCode= models.ForeignKey(PriceList,on_delete=models.CASCADE)
def __str__(self):
return '%s' % (self.priceCode)
#serializers.py
class ProductDetailsSerializer(serializers.ModelSerializer):
category= serializers.StringRelatedField(many= True, read_only= True)
price = serializers.StringRelatedField(read_only= True)
class Meta:
model = ProductDetail
fields = ('productCode', 'productName', 'manufacturer','category', 'price')