tob
tob

Reputation: 21

django blog like button error django.urls.exceptions.NoReverseMatch:

enter image description here am making a django blog and trying to implement a Like button. Anyone got any help/ideas how to get this to work when am adding the code i get some errors.

atm i got error: django.urls.exceptions.NoReverseMatch: Reverse for 'post_detail' not found. 'post_detail' is not a valid view function or pattern name.

I would really appreciate if someone could help me to get this like button up and runing since i been trying to fix it forever it feels like

newsapp folder views.py

from django.shortcuts import render, get_object_or_404, redirect
from django.views import generic
from .models import Post, Like
from .forms import CommentForm


class PostList(generic.ListView):
    queryset = Post.objects.filter(status=1).order_by('-created_on')
    template_name = 'index.html'
    paginate_by = 6

def post_view(request):
    qs = Post.objects.all()
    user = request.user

    context = {
        'qs': qs,
        'user': user,
    }

    return render(request, 'newsapp/main.html', context)

def like_post(request):
    user = request.user
    if request.method == 'POST':
        post_id = request.POST.get('post_id')
        post_obj = Post.objects.get(id=post_id)

        if user in post_obj.liked.all():
            post_obj.liked.remove(user)
        else:
            post_obj.liked.add(user)

        like, created = Like.objects.get_or_create(user=user, post_id=post_id)

        if not created:
            if like.value == 'Like':
                like.value = 'Unlike'
            else:
                like.value = 'Like'

        like.save()
    return redirect('newsapp:post-list')




def post_detail(request, slug):
    template_name = 'post_detail.html'
    post = get_object_or_404(Post, slug=slug)
    comments = post.comments.filter(active=True)
    new_comment = None
    # Comment posted
    if request.method == 'POST':
        comment_form = CommentForm(data=request.POST)
        if comment_form.is_valid():

            # Create Comment object but don't save to database yet
            new_comment = comment_form.save(commit=False)
            # Assign the current post to the comment
            new_comment.post = post
            # Save the comment to the database
            new_comment.save()
    else:
        comment_form = CommentForm()

    return render(request, template_name, {'post': post,
                                           'comments': comments,
                                           'new_comment': new_comment,
                                           'comment_form': comment_form})

newsapp folder urls.py

from django.urls import path
from . import views
from .views import post_view, like_post


app_name = 'newsapp'

urlpatterns = [
    path('', views.PostList.as_view(), name='home'),
    path("<slug:slug>/", views.post_detail, name="post_detail"),
    path('', post_view, name='post-list'),
    path('like/', like_post, name='like-post'),
]    

newsapp folder models.py

from django.db import models
from django.contrib.auth.models import User
from cloudinary.models import CloudinaryField


STATUS = (
    (0,"Draft"),
    (1,"Publish")
)

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
    updated_on = models.DateTimeField(auto_now=True)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    liked = models.ManyToManyField(User, default=None, blank=True, related_name="liked")

    class Meta:
        ordering = ['-created_on']

    def __str__(self):
        return self.title

    @property
    def num_likes(self):
        return self.liked.all().count()

LIKE_CHOICES = (
    ('Like', 'Like'),
    ('Unlike', 'Unlike'),
)

class Like(models.Model):
    User = models.ForeignKey(User, on_delete=models.CASCADE)
    Post = models.ForeignKey(Post, on_delete=models.CASCADE)
    value = models.CharField(choices=LIKE_CHOICES, default='Like', max_length=10)

    def __str__(self):
        return str(self.post)


class Comment(models.Model):
    post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
    name = models.CharField(max_length=80)
    email = models.EmailField()
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=False)

    class Meta:
        ordering = ['created_on']

    def __str__(self):
        return 'Comment {} by {}'.format(self.body, self.name)

newsapp folder forms.py

from django import forms
from .models import Comment


class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ("name", "email", "body")

newsapp folder admin.py

from django.contrib import admin
from django_summernote.admin import SummernoteModelAdmin
from .models import Post, Comment, Like


@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
    list_display = ('name', 'body', 'post', 'created_on', 'active')
    list_filter = ('active', 'created_on')
    search_fields = ('name', 'email', 'body')
    actions = ['approve_comments']

    def approve_comments(self, request, queryset):
        queryset.update(active=True)

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'slug', 'status','created_on')
    list_filter = ("status",)
    search_fields = ['title', 'content']
    prepopulated_fields = {'slug': ('title',)}

class PostAdmin(SummernoteModelAdmin):
    summernote_fields = ('content',)

admin.site.register(Post, PostAdmin)
admin.site.register(Like)

newsblog folder urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('newsapp.urls')),
    path('summernote/', include('django_summernote.urls')),
    path('newsapp/', include('newsapp.urls', namespace='newsapp')),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

newsblog folder settings.py

from pathlib import Path
import os
import dj_database_url
if os.path.isfile("env.py"):
    import env


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')




# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True



ALLOWED_HOSTS = ['newapp888.herokuapp.com', 'localhost']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'cloudinary_storage',
    'django.contrib.staticfiles',
    'cloudinary',
    'newsapp',
    'django_summernote',
    'crispy_forms',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'newsblog.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [TEMPLATES_DIR],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'newsblog.wsgi.application'


DATABASES = {
    'default': dj_database_url.parse(os.environ.get("DATABASE_URL"))
}




# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_STORAGE = 'cloudinary_storage.storage.StaticHashedCloudinaryStorage'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

CRISPY_TEMPLATE_PACK = "bootstrap4"
X_FRAME_OPTIONS = 'SAMEORIGIN'
MEDIA_URL = '/media/'
DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')


# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

templates folder base.html

<!DOCTYPE html>
<html>

    <head>
        <title>Django Central</title>
        <link href="https://fonts.googleapis.com/css?family=Roboto:400,700" rel="stylesheet">
        <meta name="google" content="notranslate" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
            crossorigin="anonymous" />
    </head>

    <body>
        <style>
            body {
            font-family: "Roboto", sans-serif;
            font-size: 17px;
            background-color: #fdfdfd;
        }
        .shadow {
            box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.1);
        }
        .btn-danger {
            color: #fff;
            background-color: #f00000;
            border-color: #dc281e;
        }
        .masthead {
            background: #3398E1;
            height: auto;
            padding-bottom: 15px;
            box-shadow: 0 16px 48px #E3E7EB;
            padding-top: 10px;
        }
    </style>

        <!-- Navigation -->
        <nav class="navbar navbar-expand-lg navbar-light bg-light shadow" id="mainNav">
            <div class="container-fluid">
                <a class="navbar-brand" href="{% url 'newsapp:home' %}">BlogNews</a>
                <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive"
                    aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarResponsive">
                    <ul class="navbar-nav ml-auto">
                        <li class="nav-item text-black">
                            <a class="nav-link text-danger font-weight-bold" href="#">Newsblog</a>
                        </li>
                        <li class="nav-item text-black">
                            <a class="nav-link text-danger font-weight-bold" href="#">AutomatedNews</a>
                        </li>
                        <li class="nav-item text-black">
                            <a class="nav-link text-danger font-weight-bold" href="#">Login</a>
                        </li>
                        <li class="nav-item text-black">
                            <a class="nav-link text-danger font-weight-bold" href="#">Register</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
        {% block content %}
        <!-- Content Goes here -->
        {% endblock content %}
        <!-- Footer -->
        <footer class="py-3 bg-grey">
            <p class="m-0 text-dark text-center ">Copyright &copy; Django Central</p>
        </footer>
    </body>
</html>

templates folder index.html

{% extends "base.html" %}
{% block content %}
<style>
    body {
        font-family: "Roboto", sans-serif;
        font-size: 18px;
        background-color: #fdfdfd;
    }

    .head_text {
        color: white;
    }

    .card {
        box-shadow: 0 16px 48px #E3E7EB;
    }
</style>

<header class="masthead">
    <div class="overlay"></div>
    <div class="container">
        <div class="row">
            <div class=" col-md-8 col-md-10 mx-auto">
                <div class="site-heading">
                    <h3 class=" site-heading my-4 mt-3 text-white"> NewsBlog and Automated news with API</h3>
                    <p class="text-light">We Love Django As much as you do..! &nbsp
                    </p>
                </div>
            </div>
        </div>
    </div>
</header>
<div class="container">
    <div class="row">
        <!-- Blog Entries Column -->
        <div class="col-md-8 mt-3 left">
            {% for post in post_list %}
            <div class="card mb-4">
                <div class="card-body">
                    <h2 class="card-title">{{ post.title }}</h2>
                    <p class="card-text text-muted h6">{{ post.author }} | {{ post.created_on}} </p>
                    <p class="card-text">{{post.content|slice:":200" }}</p>
                    <a href="{% url 'post_detail' post.slug  %}" class="btn btn-primary">Read More &rarr;</a>
                </div>
            </div>
            {% endfor %}
        </div>
        {% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}
    </div>
</div>
{%endblock%}

templates folder main.html

{% extends 'base.html' %}

{% block title %}
{% endblock title %}

{% block content %}
    {% for obj in qs %}
        <div class='ui segment'>
        <h1>{{ obj.title }}</h1>
        <p>{{ obj.body }}</p>
        <form action="{% url 'newsapp:like-post'%}" method='POST' class="ui form">
            {% csrf_token %}
            <input type='hidden' name='post_id' value="{{ obj.id}}">
            {% if user not in obj.liked.all %}
                <button class="ui button positive" type='submit'>Like</button>
            {% else %}
                <button class="ui button negative" type='submit'>Unlike</button>
            {% endif %}
            <strong>{{ obj.liked.all.count }} likes</strong>
        </form>
    </div>
    {% endfor %}
{% endblock content %}

templates folder post_detail.html

{% extends 'base.html' %} {% block content %}
    {% load crispy_forms_tags %}

    <div class="container">
        <div class="row">
            <div class="col-md-8 card mb-4  mt-3 left  top">
                <div class="card-body">
                    <h1>{% block title %} {{ post.title }} {% endblock title %}</h1>
                    <p class=" text-muted">{{ post.author }} | {{ post.created_on }}</p>
                    <p class="card-text ">{{ post.content | safe }}</p>
                </div>
            </div>
            {% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}

            <div class="col-md-8 card mb-4  mt-3 ">
                <div class="card-body">
                    <!-- comments -->
                    {% with comments.count as total_comments %}
                        <h2>{{ total_comments }} comments</h2>

                        <p>
                    {% endwith %} {% for comment in comments %}
                        </p>

                        <div class="comments" style="padding: 10px;">
                            <p class="font-weight-bold">
                                {{ comment.name }}
                                <span class=" text-muted font-weight-normal">
                                    {{ comment.created_on }}
                                </span>
                            </p>
                            {{ comment.body | linebreaks }}
                        </div>

                    {% endfor %}
                </div>
            </div>
            <div class="col-md-8 card mb-4  mt-3 ">
                <div class="card-body">
                    {% if new_comment %}
                        <div class="alert alert-success" role="alert">
                            Your comment is awaiting moderation
                        </div>
                    {% else %}
                        <h3>Leave a comment</h3>
                        <form method="post" style="margin-top: 1.3em;">
                            {{ comment_form | crispy }}
                            {% csrf_token %}
                            <button type="submit" class="btn btn-primary  btn-lg">Submit</button>
                        </form>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>

{% endblock content %}

templates folder sidebar.html

{% block sidebar %}

<style>
        .card{
            box-shadow: 0 16px 48px #E3E7EB;
        }

</style>

<!-- Sidebar Widgets Column -->
<div class="col-md-4 float-right ">
<div class="card my-4">
        <h5 class="card-header">Info</h5>
    <div class="card-body">
        <p class="card-text">Blog yourself about the Latest news or find new via the Automated news Feature! </p>
    </div>
</div>
</div>

{% endblock sidebar %}

Upvotes: 0

Views: 139

Answers (1)

DrummerMann
DrummerMann

Reputation: 857

As you did here in your base {% url 'newsapp:home' %}, you need to add the appname in with post_detail.

The snippet in index.html will thus be:

{% for post in post_list %}
<div class="card mb-4">
    <div class="card-body">
        <h2 class="card-title">{{ post.title }}</h2>
        <p class="card-text text-muted h6">{{ post.author }} | {{ post.created_on}} </p>
        <p class="card-text">{{post.content|slice:":200" }}</p>
        <a href="{% url 'newsapp:post_detail' post.slug  %}" class="btn btn-primary">Read More &rarr;</a>
        <!--              ^^^^^                -->
    </div>
</div>
{% endfor %}

Upvotes: 1

Related Questions