简体   繁体   English

如何在 Django REST Framework 序列化程序中检索具有向后关系查找的多对多字段?

[英]How to retrieve a many-to-many field with backward relationships lookup in Django REST Framework serializer?

Please correct my title if it's not correct.如果标题不正确,请更正我的标题。 My problem is I want to retrieve FinishType 's name from Product .我的问题是我想从Product检索FinishTypename I have tried 2 ways to achieve this: first attempt and second attempt .我尝试了两种方法来实现这一目标:第一次尝试第二次尝试
My simplifed related models in models.py :我在models.py简化的相关模型:

class Product(models.Model):
    product_id = models.CharField(max_length=6)
    color = models.ForeignKey(ColorParent, on_delete=models.SET_NULL, null=True)
    collection = models.ForeignKey(ProductCollection, on_delete=models.SET_NULL, null=True)

    @property
    def get_distributors(self):
        return Distributor.objects.filter(distributor__products=self).count()

    def __str__(self):
        return self.product_id

class FinishType(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

class ProductFinishType(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    market = models.ForeignKey(Market, on_delete=models.CASCADE)
    finish_types = models.ManyToManyField(FinishType)

    def __str__(self):
        return '%s - %s' % (self.product, self.market)

class ProductAlias(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    market = models.ForeignKey(Market, on_delete=models.CASCADE)
    name = models.CharField(max_length=50, null=True, blank=True)

    def __str__(self):
        return '%s - %s' % (self.product, self.name)

My serializers.py :我的serializers.py

class ProductGridSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField(source='get_name')
    finishing = serializers.SerializerMethodField('get_finish_types')
    distributor = serializers.ReadOnlyField(source='get_distributors')

    @staticmethod
    def get_name(obj):
        return [pa.name for pa in obj.productalias_set.all()]

    @staticmethod
    def get_finish_types(obj):
        return [pft.name for pft in obj.productfinishtype_set.all().select_related('finish_types')]  # first attempt

    class Meta:
        model = Product
        fields = ['id', 'product_id', 'name', 'collection', 'finishing', 'distributor']

First attempt works for name field which fetches ProductAlias 's name but gives me this error:第一次尝试的工程name ,其获取场ProductAliasname ,但给我这个错误:

FieldError at /api/product_grids/ /api/product_grids/ 处的 FieldError
Invalid field name(s) given in select_related: 'finish_types'. select_related 中给出的字段名称无效:'finish_types'。 Choices are: product, market选项是:产品、市场

My get_finish_types() on second attempt:我的get_finish_types()第二次尝试:

@staticmethod
def get_finish_types(obj):
    product_finish_types = obj.productfinishtype_set.all()
    response = ProductFinishTypeSerializer(product_finish_types, many=True, source='finish_types').data
    return response

It gives me the whole object datas:它给了我整个对象数据:

{
      "id": 1,
      "product_id": "BQ1111",
      "name": [
            "White Stone"
      ],
      "collection": 1,
      "finishing": [
          {
              "id": 1,
              "product": 1,
              "market": 1,
              "finish_types": [
                  1,
                  3,
                  5
              ]
          }
      ],
      "distributor": 5
},

My desired output is something like:我想要的输出是这样的:

{
      "id": 1,
      "product_id": "BQ1111",
      "name": [
            "White Stone"
      ],
      "collection": 1,
      "finishing": [
            "Polished",
            "Carved",
            "Melted"
      ],
      "distributor": 5
},

Create a serializer for FinishType ,FinishType创建一个序列化FinishType

class FinishTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = FinishType
        fields = ('name',)

and wire-up it in ProductGridSerializer using SerializerMethodField并使用SerializerMethodFieldProductGridSerializer连接它

class ProductGridSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField(source='get_name')    
    distributor = serializers.ReadOnlyField(source='get_distributors')
    finishing = serializers.SerializerMethodField() def get_finishing(self, product): qs = FinishType.objects.filter(productfinishtype__product=product) return FinishTypeSerializer(qs, many=True).data

    @staticmethod
    def get_name(obj):
        return [pa.name for pa in obj.productalias_set.all()]

    class Meta:
        model = Product
        fields = ['id', 'product_id', 'name', 'collection', 'finishing', 'distributor']

Inspired by @Arakkal Abu's queryset, I tried it using my first attempt.受到@Arakkal Abu 的查询集的启发,我第一次尝试使用它。
FinishTypeSerializer added in serializers.py :serializers.py添加了FinishTypeSerializer

class FinishTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = FinishType
        fields = ('name',)

ProductGridSerializer in serializers.py : serializers.py ProductGridSerializer

class ProductGridSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField(source='get_name')
    finishing = serializers.SerializerMethodField(source='get_finishing')
    distributor = serializers.ReadOnlyField(source='get_distributors')

    @staticmethod
    def get_name(obj):
        return [pa.name for pa in obj.productalias_set.all()]

    @staticmethod
    def get_finishing(product):
        return [pft.name for pft in FinishType.objects.filter(productfinishtype__product=product)]

    class Meta:
        model = Product
        fields = ['id', 'product_id', 'name', 'collection', 'finishing', 'distributor']

The JSON output is: JSON 输出为:

{
     "id": 1,
     "product_id": "BQ1111",
     "name": [
           "White Stone"
     ],
     "collection": 1,
     "finishing": [
           "Polished",
           "Honed",
           "Carved"
     ],
     "distributor": 5
},

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM