DRF 如何更改 JSON 响应中的字段键名

时间:2020-12-21 13:16:18

标签: django django-rest-framework

我想显示特定模型的所有对象,以及它的相关对象(面向对象)。 有没有办法更改/自定义 JSON 输出? (就键名、值还是嵌套而言?)

views.py

class QuestionSerializer(serializers.ModelSerializer):
    choices = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Question
        fields = '__all__'

serializers.py

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True, editable=False, name='pub_date')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='choices')
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

    def related_question(self):
        q = self.question.question_text
        return q

models.py

HTTP 200 OK
Allow: OPTIONS, GET
Content-Type: application/json
Vary: Accept

[
    {
        "id": 1,
        "choices": [
            1,
            2,
            3
        ],
        "question_text": "Question 1",
        "pub_date": "2020-12-19T23:07:25.071171+05:30"
    },
    {
        "id": 2,
        "choices": [
            4,
            5
        ],
        "question_text": "Question 2",
        "pub_date": "2020-12-21T13:58:37.595672+05:30"
    }
]

输出

choices

在输出中,pk 显示对象的 choice_text。 如何更改它以显示 depth 或自定义字符串? 另外,对象嵌套的方式可以自定义吗?

编辑:当我问是否有办法行使更多控制权时,我的意思是控制 JSON 响应的 git commit -m 'message here'

3 个答案:

答案 0 :(得分:1)

考虑使用 SlugRelatedField 而不是 PrimaryKeyRelatedField。例如:

class QuestionSerializer(serializers.ModelSerializer):
    choices = SlugRelatedField(many=True, read_only=True, slug_field='choice_text')

    class Meta:
        model = Question
        fields = '__all__'

此外,您需要使 choice_text 字段唯一,即添加 unique=True 以使其工作。

choice_text = models.CharField(max_length=200, unique=True)

仅供参考,您可以从模型定义中删除 __unicode__ 方法。可以在此 Django documentation link 中找到说明。

答案 1 :(得分:1)

如果您希望更多地控制您希望返回的内容

,您可以使用 serializers.SerializerMethodField(...)
class QuestionSerializer(serializers.ModelSerializer):
    choices = serializers.SerializerMethodField()

    def get_choices(self, question):
        return [choice.choice_text for choice in question.choices.all()]

    class Meta:
        model = Question
        fields = '__all__'

答案 2 :(得分:1)

您可以使用序列化程序的方法字段将 choices 键替换为您想要的任何相关模型字段。例如

class QuestionSerializer(serializers.ModelSerializer):
    choices = serializers.SerializerMethodField('get_choices')

    class Meta:
        model = Question
        fields = '__all__'
    
    def get_choices(self, obj):
        return obj.choices.values('choice_text').distinct() # or values('id', 'choice_text') based on your requirements

请注意,从性能角度(例如 [choice.choice_text for choice in question.choices.all()] 等)来看,值是比遍历所有对象更好的方法。

EDIT: SerializerMethodField 当我们想要运行一些自定义逻辑来填充特定字段时使用。 使用 ModelSerializer 时,source 关键字可用于访问字段(相关、非相关),甚至在与端点交互的人员需要不同名称的情况下重命名字段。

重命名示例(使用问题中提到的模型)

class QuestionSerializer(serializers.ModelSerializer):
    poll_question = serializers.CharField(source='question_text')
    class Meta:
        model = Question
        fields = '__all__'

获取 FK 相关字段的示例:

class ChoiceSerializer(serializers.ModelSerializer):
    poll_question = serializers.CharField(source='question.question_text')
    class Meta:
        model = Choice
        fields = '__all__'

This 是了解如何以及何时在 DRF 中使用 serializers 的非常好的基础读物。