You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Django REST Framework在不同视图中灵活控制字段显示?

在Django REST Framework里灵活控制字段显示与外键序列化

问题说明

用DRF开发时,怎么不用写重复代码,就能让同一个模型的字段在不同视图里按需显示/隐藏?比如现在有这两个模型:

class Realtor(models.Model):
    name = models.CharField(max_length=100)

class House(models.Model):
    name = models.CharField(max_length=100)
    address = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    realtor = models.ForeignKey(Realtor, related_name='houses', on_delete=models.CASCADE)

要实现两个需求:

  1. 一个视图只显示House的name字段,另一个视图显示所有字段;
  2. 查询House时,显示关联Realtor的name,而不是默认的ID。

一、按需控制House字段的显示

不用写多个重复的Serializer,有这两种简洁的办法:

1. 基础Serializer+继承扩展

先写一个包含所有字段的基础Serializer,其他Serializer继承它再调整字段:

from rest_framework import serializers

# 基础Serializer,包含House所有字段
class BaseHouseSerializer(serializers.ModelSerializer):
    class Meta:
        model = House
        fields = '__all__'

# 只显示name的精简版Serializer,继承基础类指定字段
class MinimalHouseSerializer(BaseHouseSerializer):
    class Meta(BaseHouseSerializer.Meta):
        fields = ('name',)

# 如果需要保留大部分字段,用exclude更方便(比如排除address、price、realtor)
# class MinimalHouseSerializer(BaseHouseSerializer.Meta):
#     exclude = ('address', 'price', 'realtor')

然后在视图里分别用这两个Serializer就行:

from rest_framework import viewsets

# 只显示name的视图
class MinimalHouseViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = House.objects.all()
    serializer_class = MinimalHouseSerializer

# 显示所有字段的视图
class FullHouseViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = House.objects.all()
    serializer_class = BaseHouseSerializer

2. 动态控制Serializer字段

如果想在同一个视图里根据场景切换(比如列表页显示精简,详情页显示完整),可以给Serializer加动态逻辑:

class DynamicHouseSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        # 取出传入的exclude_fields参数,默认空列表
        exclude_fields = kwargs.pop('exclude_fields', [])
        super().__init__(*args, **kwargs)
        
        # 删除不需要的字段
        for field in exclude_fields:
            if field in self.fields:
                del self.fields[field]

    class Meta:
        model = House
        fields = '__all__'

然后在视图里重写get_serializer方法传参数:

class HouseViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = House.objects.all()

    def get_serializer(self, *args, **kwargs):
        # 列表页显示精简字段,详情页显示全部
        if self.action == 'list':
            kwargs['exclude_fields'] = ['address', 'price', 'realtor']
        return super().get_serializer(*args, **kwargs)

二、显示Realtor的name而非ID

要把外键的ID换成关联对象的name,常用三种方式:

1. 用StringRelatedField

如果你的Realtor模型的__str__方法返回的是name(比如def __str__(self): return self.name),直接用这个字段就行:

class BaseHouseSerializer(serializers.ModelSerializer):
    realtor = serializers.StringRelatedField()

    class Meta:
        model = House
        fields = '__all__'

注意:这个字段是只读的,要是需要支持创建/更新House时传入数据,得换其他方法。

2. 嵌套Realtor Serializer

如果以后要给Realtor加更多显示字段,这种方式更灵活:

# 先写Realtor的Serializer,只返回name
class RealtorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Realtor
        fields = ('name',)

# 在House的Serializer里嵌套使用
class BaseHouseSerializer(serializers.ModelSerializer):
    realtor = RealtorSerializer()

    class Meta:
        model = House
        fields = '__all__'

如果需要支持写入(比如创建House时关联Realtor),得重写Serializer的create或update方法来处理嵌套逻辑。

3. 用SlugRelatedField

要是想在创建/更新House时,直接传入Realtor的name来关联(而不是ID),用这个字段最合适:

class BaseHouseSerializer(serializers.ModelSerializer):
    realtor = serializers.SlugRelatedField(
        slug_field='name',  # 指定用Realtor的name字段
        queryset=Realtor.objects.all()
    )

    class Meta:
        model = House
        fields = '__all__'

这个字段既能显示Realtor的name,也支持写入时通过name关联对象。


内容的提问来源于stack exchange,提问作者matthias3132

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:50:17