在 Django Rest Framework 中转储自定义过滤字段作为响应

Dump A Custom Filtered Field as Response in Django Rest Framework

blog/models.py

class Tag(models.Model):
    label = models.SlugField(null=False, blank=False, unique=True)
    # (iii) or here?

# ...

class Entry(models.Model):
    title = models.CharField(null=False, blank=False, max_length=128)
    content = models.TextField(null=False, blank=False)
    slug = models.SlugField(unique=True)
    tags = models.ManyToManyField(Tag, null=False, blank=False)
    dtime_created = models.DateTimeField(null=False, blank=False, auto_now_add=True)

api/serializers.py

from blog.models import *

from rest_framework import serializers

class EntrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Entry
        fields = ("title", "content")

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ("label")
        # (ii) here?

api/views.py

class TagList(APIView):
    def search_by_query(self, query):
        try:
            return Tag.objects.filter(label__icontains=re.escape(query))
            # (i) do something here?
        except Tag.DoesNotExist:
            raise Http404

    def get(self, request, format=None):
        q = None
        try:
            q = request.POST["q"]
        except KeyError:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        tags = self.search_by_query(query)
        serializer = TagSerializer(tags, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        if not request.user.is_authenticated():
            return Response(status=status.HTTP_403_FORBIDDEN)

        serializer = TagSerializer(request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

我的问题有点复杂。现在,我有一个被 Entry 模型使用的 Tag 模型。然后,我创建了一个名为 TagListAPIView,它会转储包含标签的字符串。但是,问题是,我还想转储标签在 Entry 个实例中使用了多少次,如下所示:

# This is similiar to how it dumps
[
    {
        "label": "a-label-here"
    },
    {
        "label": "another-label-here"
    }
]

# This is what I want
[
    {
        "label": "a-label-here",
        "length": 5
    },
    {
        "label": "another-label-here",
        "length": 15
    }
]

怎么做?


环境

非常简单 - 使用 DRF 的 source 核心参数。

第 1 步

在您的 Tag 模型上定义一个计算任何标签出现次数的方法:

class Tag(models.Model):
    label = models.SlugField(null=False, blank=False, unique=True)

    def nr_of_entries(self):
        return self.entry_set.count()

第 2 步

然后在您的 TagSerializer 上添加一个自定义字段,该字段将从您在上面定义的方法中获取数据:

class TagSerializer(serializers.ModelSerializer):
    length = serializers.IntegerField(source="nr_of_entries", read_only=True)
    class Meta:
        model = Tag
        fields = ("label", "length")

现在,当 tag 的一个实例将被序列化时,它将包含一个 length 属性,它将从 运行 的结果中获取它的值该 tag 实例上的 nr_of_entries 方法。