Python中Django rest framework的serializers如何处理manytomany关系问题

Django rest framework 中的 serializers 的代码如下:

class AirshipDeviceCreateSerializer(serializers.ModelSerializer):
    # 获取当前登录的用户,HiddenField 不采用用户的输入而使用默认
    # user 是多对多的外键
    user = serializers.HiddenField(
         default=serializers.CurrentUserDefault()
    )
class Meta:
    model = AirshipDevice
    fields = ('user', 'name', 'type', 'device_id')

其中 user 相应的多对多的外键,我想直接获取当前用户进行保存,不用输入,但这样写会提示 user model is not iterable,我猜想多对多应该不是这样写,但我没有思路不知道怎么写?问一下大家有没有经验提示一下?

我尝试过使用 ModelSerializer 的 Listfield,不知道是不是我写的不正确,使用失败


Python中Django rest framework的serializers如何处理manytomany关系问题

1 回复

在Django REST framework里处理多对多关系,主要看你是要读数据还是写数据。

1. 读取数据(序列化)

最简单的就是用serializers.StringRelatedField或者serializers.PrimaryKeyRelatedField,直接显示关联对象的名字或者ID:

from rest_framework import serializers
from .models import Book, Author

class BookSerializer(serializers.ModelSerializer):
    # 显示作者的名字
    authors = serializers.StringRelatedField(many=True)
    # 或者显示作者的ID
    # authors = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    
    class Meta:
        model = Book
        fields = ['id', 'title', 'authors']

如果你想在嵌套里显示更多作者信息,就写个完整的AuthorSerializer

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = ['id', 'name', 'email']

class BookSerializer(serializers.ModelSerializer):
    authors = AuthorSerializer(many=True, read_only=True)
    
    class Meta:
        model = Book
        fields = ['id', 'title', 'authors']

2. 写入数据(反序列化)

写数据的时候,默认只支持通过ID列表来创建或更新关系:

class BookSerializer(serializers.ModelSerializer):
    authors = serializers.PrimaryKeyRelatedField(
        many=True, 
        queryset=Author.objects.all()  # 必须提供queryset
    )
    
    class Meta:
        model = Book
        fields = ['id', 'title', 'authors']

# 创建时传作者ID列表
data = {
    'title': 'Python编程',
    'authors': [1, 2, 3]  # 作者ID列表
}
serializer = BookSerializer(data=data)

如果你想要更复杂的写入逻辑,比如通过名字而不是ID来关联,就得自己写create()update()方法:

class BookSerializer(serializers.ModelSerializer):
    author_names = serializers.ListField(
        child=serializers.CharField(),
        write_only=True  # 只用于写入,不返回
    )
    
    class Meta:
        model = Book
        fields = ['id', 'title', 'authors', 'author_names']
        extra_kwargs = {
            'authors': {'read_only': True}  # 不让直接写authors字段
        }
    
    def create(self, validated_data):
        author_names = validated_data.pop('author_names')
        book = Book.objects.create(**validated_data)
        
        # 根据名字查找或创建作者
        for name in author_names:
            author, _ = Author.objects.get_or_create(name=name)
            book.authors.add(author)
        
        return book

总结建议:根据你的业务需求选择合适的序列化字段类型。

回到顶部