'In DRF how do I serialize a related model(OneToOne) and display the data not in a list data type but single value instance?
The code is given below with the present output and expected output. Please help if, Thank you.
In the ProductPriceMapping table the ProductDetail table and PriceList is related with a OneToOne relation, but When the data for Price is fetched with related_name= argument there must be one value for one product, but the data is being displayed is List data type.
##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')
The API as it looks:
[
{
"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"
}
]```
Solution 1:[1]
Thank you guys, I solved in this way:
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')
Solution 2:[2]
In your case, the price field is not a one-to-one related field, you either need to change the productCode to OneToOneField or if you don't want to change the DB field, you can achieve the same result simply with SerializerMethodField. In the first case, removing many=True argument from the serializer field should help. In second case, SerializerMethodField will help you to make your custom representation, e.g.:
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())
Solution 3:[3]
One simple way is to use 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
but if you want to show all of the priceList fields based on your other serializer you can do something like:
class ProductPriceMappingSerializer(serializers.ModelSerializer):
priceCode = ProductPriceListSerializer()
class Meta:
model= ProductPriceMapping
fields= ('productPriceCode','productCode', 'priceCode')
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Javad Nikbakht |
| Solution 2 | |
| Solution 3 | Roham |
