1

I know there are few similar questions here but no solutions proferred in them helped me so far. I have been on this for hours, so i will appreciate any assistance. I am using Django rest Framework to build an API. I have my models, serializers and views set up as follows:

My model

class Category(models.Model):
    name = models.CharField(max_length=40, unique=True)
    slug = models.SlugField()
    created = models.DateTimeField(auto_now_add=True)

class Post(models.Model):
    title = models.CharField(max_length=100, null=False, blank=False)
    body= models.TextField(max_length=2000, null=False, blank=False)
    owner = models.OneToOneField(User, on_delete=models.CASCADE)
    slug = models.SlugField(unique=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    image = models.ImageField(upload_to="profiles", default='profiles/no_image.png', blank=True, null=True)
    created = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-created']

    #signal to create slug on save
    def pre_save_post_slug(sender, instance, *args, **kwargs):
        if not instance.slug:
        instance.slug = slugify(instance.title)

    # connect signal to model;
    pre_save.connect(pre_save_post_slug, sender=Post)

My Serializer.py:

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ['id', 'name', 'slug']
        extra_kwargs = {
            'name': {
                'validators': []
            }
        }

class PostSerializer(serializers.ModelSerializer):
    owner = UserSerializer()
    image = serializers.ImageField(max_length=None)
    category = CategorySerializer(read_only=False)

    class Meta:
        model = Post
        fields = ['id', 'title', 'body', 'owner', 'slug', 'category', 'image', 'created']
    
    def get_image(self, obj):
        request = self.context.get('request')
        image = obj.image.url
        return request.build_absolute_uri(image)

    def create(self, validated_data):
        title = validated_data.get('title')
        body = validated_data.get('body')
        slug = slugify(title)
        image = validated_data.get('image', None)

        category_data = validated_data.pop('category')
        cat_id = category_data.get('id')
        if cat_id:
            category = Category.objects.get(id=cat_id)

        post= Post.objects.create(title=title, body=body, category=category, slug=slug, image=image)
        return post

My views.py:

class PostCreateAPIView(CreateAPIView):
    serializer_class = PostSerializer
    queryset = Post.objects.all()
    permission_classes = [IsAuthenticated,]
    authentication_classes = [TokenAuthentication,]

    def create(self, request, *args, **kwargs):
        context = {
            'request': request
        }
        serializer = self.get_serializer(data=request.data, context=context)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        response = {'message': 'Post has been created!', 'result': serializer.data}
        return Response(response, status=status.HTTP_201_CREATED)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user, created=timezone.now())

my urls.py:

path('api/post/create/', PostCreateAPIView.as_view(), name="create-post")

Now when i make a post request to that endpoint, i keep getting this error:

{errors: [{field: "owner", message: ["This field is required"]},
   0: {field: "owner", message: ["This field is required"]}
   1: {field: "slug", message: ["This field is required"]}
   2: {field: "created", message: ["This field is required"]}

meaning my views perform_create did not run, also the slug = slugify(title) line in my serializer.

2 Answers 2

3

Try putting owner in read_only_fields in serializer class

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your assistance @ZirconS. I changed all the fields with error to read_only=True and it worked.
0

Add user as a hidden field in your PostSerializer and get ride of perform_create

class PostSerializer(serializers.ModelSerializer)
   user = serializers.HiddenField(default=serializers.CurrentUserDefault())

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.