【问题标题】:In DRF how do I serialize a related model(OneToOne) and display the data not in a list data type but single value instance?在 DRF 中,我如何序列化相关模型(OneToOne)并显示数据而不是列表数据类型,而是单值实例?
【发布时间】:2022-12-12 09:17:22
【问题描述】:

下面给出了代码以及当前输出和预期输出。 在 ProductPriceMapping 表中,ProductDetail 表和 PriceList 与 OneToOne 关系相关,但是当使用 related_name 参数获取价格数据时,一种产品必须有一个值,数据正在显示是 list 数据类型。

模型.py

from django.db import models

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)

序列化器.py

from rest_framework import serializers
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
        ]
    }
]

预期结果:

[
    {
        "productCode": 1,
        "productName": "NeoChef",
        "manufacturer": "LG",
        "category": [
            "1: Microwave Oven"
        ],
        "price": "26000.0"  
    }
]```

【问题讨论】:

  • ProductPrice 映射到 Product Detail 关系是一个外键,这意味着“价格”可以返回许多相关对象,它不是 OneToOne 关系
  • 当使用与 ProductDetail 的 OneToOne 关系时,有一个回溯说“‘ProductPriceMapping’对象不可迭代”
  • @Roham 哪条线?

标签: python django django-models django-rest-framework


【解决方案1】:

在您的情况下,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())

【讨论】:

  • 已经尝试过了,但它看起来像“价格”:app.ProductPriceMapping.None
  • @JabedAkhtar 更新了答案
【解决方案2】:

一种简单的方法是使用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')

【讨论】:

    【解决方案3】:

    谢谢各位,我是这样解决的:

    模型.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)
    

    序列化程序.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')
    

    【讨论】:

      猜你喜欢
      • 2021-03-23
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-19
      • 2012-08-06
      相关资源
      最近更新 更多