在DRF中使用Serializer同时获取StringRelatedField与PrimaryKeyRelatedField
别担心,新手遇到这种摸不着头绪的问题太正常啦!我来帮你搞定在DRF序列化器里同时拿到关联字段的主键和显示名称的需求~
先结合你给出的模型代码,给你两种常用的解决方案:
方法一:用嵌套序列化器(推荐,更规范)
这种方式适合需要重复使用关联字段序列化逻辑的场景,先给关联的Materia模型写一个极简的序列化器,只返回你需要的主键和名称字段:
class MateriaSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() # 这里替换成Materia模型里实际用来显示的字段,比如你定义的__str__对应的字段
然后在TemaPai的序列化器里直接嵌套这个序列化器,处理多对多关系:
class TemaPaiSerializer(serializers.ModelSerializer): # 多对多关系要加上many=True disciplines = MateriaSerializer(many=True, read_only=True) class Meta: model = TemaPai fields = ['id', 'subject', 'disciplines']
如果是处理TemaPaiOrdem里的外键关联(比如discipline字段),同样套用这个逻辑:
class TemaPaiOrdemSerializer(serializers.ModelSerializer): # 嵌套subject的信息 subject = serializers.SerializerMethodField() # 嵌套discipline的信息 discipline = MateriaSerializer(read_only=True) def get_subject(self, obj): # 直接用TemaPai的__str__方法拿到显示文本,同时返回主键 return { 'id': obj.subject.id, 'name': str(obj.subject) } class Meta: model = TemaPaiOrdem fields = ['id', 'subject', 'discipline']
方法二:用SerializerMethodField(灵活快捷)
如果只是临时需要构造返回格式,不想单独写嵌套序列化器,可以直接用SerializerMethodField自定义返回内容:
class TemaPaiSerializer(serializers.ModelSerializer): disciplines = serializers.SerializerMethodField() def get_disciplines(self, obj): # 遍历所有关联的discipline,构造包含主键和名称的字典列表 return [ {'id': dis.id, 'name': str(dis)} for dis in obj.disciplines.all() ] class Meta: model = TemaPai fields = ['id', 'subject', 'disciplines']
兼顾读写的场景
如果你的序列化器需要支持写入操作(比如创建/更新TemaPai时传入discipline的主键),可以把主键字段设为只写,显示字段设为只读:
class TemaPaiSerializer(serializers.ModelSerializer): # 写入时传主键列表,只写 discipline_ids = serializers.PrimaryKeyRelatedField( queryset=Materia.objects.all(), many=True, source='disciplines', write_only=True ) # 读取时返回带名称的详细信息,只读 disciplines = serializers.SerializerMethodField(read_only=True) def get_disciplines(self, obj): return [{'id': dis.id, 'name': str(dis)} for dis in obj.disciplines.all()] class Meta: model = TemaPai fields = ['id', 'subject', 'discipline_ids', 'disciplines']
这样写接口的时候传discipline_ids(比如[1,3,5]),读接口的时候就能拿到包含主键和名称的disciplines列表啦~
内容的提问来源于stack exchange,提问作者Luis Rock
相关产品推荐
相关产品推荐

