如何使用 django rest 框架保存多对多字段对象

Posted

技术标签:

【中文标题】如何使用 django rest 框架保存多对多字段对象【英文标题】:How do i save many to many fields objects using django rest framework 【发布时间】:2017-01-17 05:39:30 【问题描述】:

我有三个模型博客、已发布、标签。在 Blogs 模型中,我将字段“postedin”作为 Posted 模型的外键,将“tags”字段作为 Tags 模型的 manytomany 字段。

models.py:

class Posted(models.Model):
    name = models.CharField(_('Posted In'),max_length=255, unique=True)

class Tags(models.Model):
    name = models.CharField(_('Tag Name'),max_length=255, unique=True)

class Blogs(models.Model):
    author = models.ForeignKey(CustomUser)
    title=models.CharField(max_length=100)
    postedin=models.ForeignKey(Posted)
    tags= models.ManyToManyField(Tags)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

views.py:

class BlogViewSet(viewsets.ModelViewSet):
    queryset=Blogs.objects.order_by('-created_at')
    serializer_class= BlogsSerializer

def get_permissions(self):
    if self.request.method in permissions.SAFE_METHODS:
        return (permissions.AllowAny(),)
    return (permissions.IsAuthenticated(),IsAuthorOfBlog())

def perform_create(self,serializer):

    serializer.save(author=self.request.user)

    return super(BlogViewSet,self).perform_create(serializer)

serializers.py:

class TagsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tags

        fields = ('pk','name')
        read_only_fields=('pk','name')

class PostedSerializer(serializers.ModelSerializer):
    class Meta:
        model = Posted

        fields = ('pk','name')
        read_only_fields=('pk','name')

class BlogsSerializer(serializers.ModelSerializer):
    author = AccountSerializer(read_only=True,required=False)
    tags=TagsSerializer(read_only=True,many=True)
    tags_id = serializers.PrimaryKeyRelatedField(queryset=Tags.objects.all(), write_only=True)
    postedin = PostedSerializer(read_only=True)
    postedin_id = serializers.PrimaryKeyRelatedField(queryset=Posted.objects.all(), write_only=True)

    class Meta:
        model = Blogs

        fields = ('pk','author','title','tags','tags_id','postedin','postedin_id','content','created_at','updated_at')
        read_only_fields=('pk','created_at','updated_at')


    def get_validation_exclusions(self, *args, **kwargs):
        exclusions = super(BlogsSerializer, self).get_validation_exclusions()

        return exclusions + ['author']
    def create(self, validated_data):
        postedin = validated_data.pop('postedin_id')
        tags = validated_data.pop('tags_id')
        blogs = Blogs.objects.create(tags=tags,postedin=postedin, **validated_data)
        return blogs

请求已发送:

标题:“nvnbv”,postedin_id:“1”,tags_id:[“2”,“5”,“1”,“4”],内容:“nmvmvjm”

回复收到:

tags_id: ["类型不正确。预期的pk值,收到的列表。"]

我是 Django-rest-framework 的初学者。如何解决这个错误。

提前致谢!

【问题讨论】:

你试过serializers.PrimaryKeyRelatedField(queryset=Tags.objects.all(), write_only=True, many=True)吗? @Abdulafaja 收到错误“'tags' is an invalid keyword argument for this function” 哪个函数?给出所有错误 @Abdulafaja。应用您的建议后。在'def create(self,validated_data)'函数中 docs.djangoproject.com/es/1.10/topics/db/examples/many_to_many 在创建博客之前您不能关联 ManyToMany 字段 【参考方案1】:

感谢@Abdulafaja 的建议。

终于找到解决办法了

BlogsSerializer 应该是

class BlogsSerializer(serializers.ModelSerializer):
    author = AccountSerializer(read_only=True,required=False)
    tags=TagsSerializer(read_only=True,many=True)
    tags_id = serializers.PrimaryKeyRelatedField(queryset=Tags.objects.all(), write_only=True,many=True)
    postedin = PostedSerializer(read_only=True)
    postedin_id = serializers.PrimaryKeyRelatedField(queryset=Posted.objects.all(), write_only=True)

    class Meta:
        model = Blogs

        fields = ('pk','author','title','tags','tags_id','postedin','postedin_id','content','created_at','updated_at')
        read_only_fields=('pk','created_at','updated_at')


    def get_validation_exclusions(self, *args, **kwargs):
        exclusions = super(BlogsSerializer, self).get_validation_exclusions()

        return exclusions + ['author']
    def create(self, validated_data):
        postedin = validated_data.pop('postedin_id')
        tags = validated_data.pop('tags_id')
        blogs = Blogs.objects.create(postedin=postedin, **validated_data)
        for tg in tags:
            blogs.tags.add(tg)
        return blogs

【讨论】:

【参考方案2】:

不用循环,你可以简单地使用这一行blogs.tags.add(*tg)

def create(self, validated_data):
    postedin = validated_data.pop('postedin_id')
    tags = validated_data.pop('tags_id')
    blogs = Blogs.objects.create(postedin=postedin, **validated_data)
    blogs.tags.add(*tg)
    return blogs

【讨论】:

以上是关于如何使用 django rest 框架保存多对多字段对象的主要内容,如果未能解决你的问题,请参考以下文章

完全迷失:在 Django Rest 框架中使用序列化器和更新的多对多

django rest框架保存base64文件

如何在 django rest 框架中仅使用特定变体对象将项目添加到愿望清单?

Django REST框架:在ModelViewSet中保存相关模型

如何使用 Django Rest Framework 向 ManyToMany 字段添加数据?

Django REST框架:POST请求:仅在数据不存在时如何保存数据