Mominul Islam Rasel
Mominul Islam Rasel

Reputation: 13

Form post request running wrong view method on Django

I'm trying to clone the Instagram web page using Django(version-3.1). My Django project has an app called 'post'. One of its template I have a form which is posting a comment to a post. The form post request should call the path('add_comment/',views.add_comment,name='add_comment'), but It's calling path('<slug:slug>/',views.post_details,name='post_details'), instead. And raising DoesNotExist at /post/add_comment error. I added print() statement at the beginning of both add_comment() and post_details() methods to find out which is running when the request is made. I have no idea what I have done wrong.

The project GitHub link - https://github.com/mirasel/Instagram_Clone

the post_details.html template is -

{% extends 'base.html' %}
{% load static %}
{% block title %} post {% endblock %}
{% block profilephoto %} {{ propic.url }} {% endblock %}
{% block body %}
    <div>
        <div>
            <img src="{{post.image.url}}" alt="post" height="250px" width="250px">
        </div>
        <div>
            <a href="{% url 'instagram:profile' post.uploader %}">
                <img src="{{uploader.profile_pic.url}}" alt="{{uploader}}" style="border-radius: 50%;" height="24px" width="24px">
                 {{ post.uploader }}
            </a><br>
            <p>{{ post.date_published.date }}</p>
        </div>
        <div>
            <p>{{ post.caption }}</p>
        </div>
        <div>
            <form action="{% url 'post:add_comment' %}" id="comment_form" method="POST">
                {% csrf_token %}
                <textarea name="comment" id="comment" cols="30" rows="1" placeholder="Write a comment..."></textarea>
                <input type="hidden" name="slug" id="slug" value="{{post.slug}}">
                <!-- <input type="submit" style="display: none;" name="submit"> -->
            </form>
    <script>
        $(function(){
            $("#comment").keypress(function (e) {
                if(e.which == 13 && !e.shiftKey) {        
                    $(this).closest("form").submit();
                    e.preventDefault();
                }
            });
        });
    </script>
{% endblock %}

the views.py -

from django.shortcuts import render,redirect
from instagram.views import get_nav_propic,get_profile_details
from .models import UserPost,PostComment,PostLike
from django.http import JsonResponse

def get_post_likes(post):
    likes = PostLike.objects.filter(post=post)
    total_likes = len(likes)
    likers = []
    for l in likes:
        likers.append(get_profile_details(l.liker))
    return {'likers':likers,'total_likes':total_likes}


def get_post_comments(post):
    comments = PostComment.objects.filter(post=post)
    total_comments = len(comments)
    commenter = []
    comment = []
    for c in comments:
        commenter.append(get_profile_details(c.commenter))
        comment.append(c.comment)
    postcomment = zip(commenter,comment)
    return {'post_comment':postcomment,'total_comments':total_comments}


def upload_post(request):
    if request.method == 'POST':
        image = request.FILES['post_img']
        caption = request.POST['caption']
        uploader = request.user
        UserPost.objects.create(uploader=uploader,image=image,caption=caption)
        return redirect('instagram:feed')
    else:
        context = {
            'propic' : get_nav_propic(request.user)
        }
        return render(request,'post/upload_post.html',context)

def post_details(request,slug):
    print('I am here in post details')
    post = UserPost.objects.get(slug=slug)
    context = {
        'propic'    : get_nav_propic(request.user),
        'post'      : post,
        'uploader'  : get_profile_details(post.uploader),
        'LIKES'     : get_post_likes(post),
        'COMMENTS'  : get_post_comments(post),
    }
    return render(request,'post/post_details.html',context)

def add_comment(request):
    print('I am here in add comment')
    if request.method == 'POST':
        post_slug = request.POST.get('slug')
        post = UserPost.objects.get(slug=post_slug)
        user = request.user
        comment = request.POST.get('comment')
        PostComment.objects.create(post=post,commenter=user,comment=comment)
        return redirect('post:post_details',slug=post_slug)

the urls.py -

from django.urls import path
from . import views

app_name='post'

urlpatterns = [
    path('upload_post/',views.upload_post,name='upload_post'),
    path('<slug:slug>/',views.post_details,name='post_details'),
    path('add_comment/',views.add_comment,name='add_comment'),

]

The error - Error page

Solved I had to make the URL path of add_comment as following-

#previous one
path('add_comment/',views.add_comment,name='add_comment'),

#modified one
path('comment/add_comment/',views.add_comment,name='add_comment'),

This is because the pattern for the slug URL and add comment URL were similar.

Upvotes: 0

Views: 836

Answers (1)

adnanmuttaleb
adnanmuttaleb

Reputation: 3624

Because Django will process the urlpatterns sequentially, from docs:

Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL, matching against path_info.

And '/add_comment' is a valid slug <slug:slug>, so post_details will be called.

So you should keep the definition of the most generic url patterns at last:

urlpatterns = [
    path('upload_post/',views.upload_post,name='upload_post'),
    path('add_comment/',views.add_comment,name='add_comment'),
    path('<slug:slug>/',views.post_details,name='post_details'),
]

Hopefully this will work for you.

Upvotes: 1

Related Questions