Search code examples
javascriptdjangodjango-viewsfetch-apidom-manipulation

Fetch API PUT method not updating database


I have posts on my webpage that are being displayed via a Fetch API 'POST' method and I managed to create a like/dislike button for each post that toggles back and forth when clicked. The like count displayed next to the post updates when the post is liked or disliked but on refreshing the page all values reset so nothing is being updated in the database. Also when I go to the Fetch API route for that post, the likes count has not changed.

This is a Django project. The like/dislike button are working on a Fetch API 'PUT' method that I created in views.py but I obviously haven't created it correctly. I am getting a "PUT 403 (Forbidden)" error in console.

models.py

class Post(models.Model):
    creator = models.ForeignKey("User", on_delete=models.CASCADE, related_name="post_creator")
    content = models.TextField(max_length=250, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    likes = models.IntegerField(blank=True, default=0)

    def serialize(self):
        return {
            "id": self.id,
            "creator": self.creator.username,
            "content": self.content,
            "created": self.created.strftime("%d %b %Y, %H:%M"),
            "likes": self.likes
        }

views.py

def post(request, post_id):

    try:
        post = Post.objects.get(creator=request.user, pk=post_id)
    except Post.DoesNotExist:
        return JsonResponse({"error": "No post found."}, status=404)


    if request.method == "GET":
        return JsonResponse(post.serialize())

    elif request.method == "PUT":
        data = json.loads(request.body)
        post.likes = int(data.get("likes")) + 1
        post.save()
        return HttpResponse(status=204)
    
    else:
        return JsonResponse({
            "error": "GET or PUT request required."
        }, status=400)

index.js

function likePost(post_id) {
    fetch(`/posts/${post_id}`)
    .then(response => response.json())
    .then(post => {

        let like = document.getElementById(`like-count-${post.id}`);
        console.log(like);
        let likeCount = parseInt(like.innerText);
        console.log("Number of likes: " + likeCount);
        like.innerText = `${++likeCount}`;

        fetch(`/posts/${post_id}`, {
            credentials: 'include',
            method: 'PUT',
            headers: {
                'Content-Type': 'application/json',
                "Access-Control-Allow-Origin" : "*", 
                "Access-Control-Allow-Credentials" : true 
            },
            body: JSON.stringify({
                likes: likeCount
            })
        })
        .then(response => response.json())
        .then(post => {
            console.log(`Post ${post.id} likes is now: ${post.likes}`);

        })

    })
}

Please let me know if I need to include more information.


Solution

  • In case it helps anyone else, I was missing @csrf_exempt above the post function. I did also realise that since I was only making a minor change to my resource it is better practice to use a PATCH method instead of PUT.

    @csrf_exempt
    @login_required
    def post(request, post_id):
    
        try:
            post = Post.objects.get(pk=post_id)
        except Post.DoesNotExist:
            return JsonResponse({"error": "No post found."}, status=404)
    
    
        if request.method == "GET":
            return JsonResponse(post.serialize())
    
        elif request.method == "PATCH":
            data = json.loads(request.body)
            post.likes = data["likes"]
            post.save()
            return HttpResponse(status=204)
        
        else:
            return JsonResponse({
                "error": "GET or PATCH request required."
            }, status=400)