Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i save many to many fields objects using django rest framework

I have three models Blogs, Posted, Tags. In Blogs model I have fields 'postedin' as foreign key to Posted model and 'tags' as manytomany fields to Tags model.

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

Request sent:

{title: "nvnbv", postedin_id: "1", tags_id: ["2", "5", "1", "4"], content: "nmvmvjm"}

response receive:

{tags_id: ["Incorrect type. Expected pk value, received list."]}

I am beginner in Django-rest-framework.How to solve this error.

Thanks in advance !

like image 874
Deep 3015 Avatar asked Sep 09 '16 06:09

Deep 3015


People also ask

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.

What is QuerySet in django REST framework?

The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects. The default behavior of REST framework's generic list views is to return the entire queryset for a model manager.

What is renderers in django REST framework?

Renderers are used to serialize the response into a specific media type like JSON, XML, YAML, etc. Django REST Framework provides various built-in renderer classes and it also supports to write a custom renderer. We specify renderers as an iterable type (i.e tuple, list, set, etc.).


2 Answers

thanks @Abdulafaja for your suggestion.

Finally I got solution

BlogsSerializer should be

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
like image 133
Deep 3015 Avatar answered Sep 20 '22 10:09

Deep 3015


Instead of loop, you can simply use this line 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
like image 41
Gm Zulkar Nine Avatar answered Sep 20 '22 10:09

Gm Zulkar Nine