improperly configured at /18/delete, Django views issue

Question:

I have searched through the other questions similar to my own problem and have come to no solution so im hoping someone can help me figure out where i went wrong.

I’m trying to implement a delete post option in my blog program but it is throwing the following error once you click the ‘delete’ button:

ImproperlyConfigured at /18/delete/
Deletepost is missing a QuerySet. Define Deletepost.model, Deletepost.queryset, or override Deletepost.get_queryset().

I am nearly sure its a problem with my URLS.py though what exactly i cannot figure out.

the following is the code in question:

Views.py

# delete post
class Deletepost(LoginRequiredMixin, DeleteView):
    form_class = Post
    success_url = reverse_lazy('blog:home')
    template_name = 'templates/post.html'

    def test_func(self):
        post = self.get_object()
        if self.request.user == post.author:
            return True
        return False

urls.py

urlpatterns = [
    # home
    path('', views.postslist.as_view(), name='home'),

    # add post
    path('blog_post/', views.PostCreateView.as_view(), name='blog_post'),

    # posts/comments
    path('<slug:slug>/', views.postdetail.as_view(), name='post_detail'),

    # edit post
    path('<slug:slug>/edit/', views.Editpost.as_view(), name='edit_post'),

    # delete post
    path('<int:pk>/delete/', views.Deletepost.as_view(), name='delete_post'),

    # likes
    path('like/<slug:slug>', views.PostLike.as_view(), name='post_like'),

]

post.html

     {% extends 'base.html' %} {% block content %}
 {% load crispy_forms_tags %}
 <div class="masthead">
    <div class="container">
        <div class="row g-0">
            <div class="col-md-6 masthead-text">
                <!-- Post title goes in these h1 tags -->
                <h1 class="post-title text-success">{{ post.title }}</h1>
                <!-- Post author goes before the | the post's created date goes after -->
                <p class="post-subtitle text-success">{{ post.author }} | {{ post.created_on }}</p>
            </div>
            <div class="d-none d-md-block col-md-6 masthead-image">
                <!-- The featured image URL goes in the src attribute -->
                {% if "placeholder" in post.featured_image.url %}
                <img src="https://codeinstitute.s3.amazonaws.com/fullstack/blog/default.jpg" width="100%">
                {% else %}
                <img src=" {{ post.featured_image.url }}" width="100%">
                {% endif %}
            </div>
        </div>
    </div>
</div>

<div class="container">
    <div class="row">
        <div class="col card mb-4  mt-3 left  top">
            <div class="card-body text-dark">
                <!-- The post content goes inside the card-text. -->
                <!-- Use the | safe filter inside the template tags -->
                <p class="card-text text-dark">
                    {{ post.content | safe }}
                </p>
                <div class="row">

                    <div class="col-1">
                        <strong>
                            {% if user.is_authenticated %}
                            <form class="d-inline" action="{% url 'post_like' post.slug %}" method="POST">
                                {% csrf_token %}
                                {% if liked %}
                                <button type="submit" name="blogpost_id" value="{{post.slug}}" class="btn-like"><i class="fas fa-heart"></i></button>
                                {% else %}
                                <button type="submit" name="blogpost_id" value="{{post.slug}}" class="btn-like"><i class="far fa-heart"></i></button>
                                {% endif %}
                            </form>
                            {% else %}
                            <span class="text-secondary"><i class="far fa-heart"></i></span>
                            {% endif %}
                        <!-- The number of likes goes before the closing strong tag -->
                        <span class="text-secondary">{{ post.number_of_likes }} </span>
                        </strong>
                    </div>
                    <div class="col-1">
                        {% with comments.count as total_comments %}
                        <strong class="text-dark"><i class="far fa-comments"></i>
                            <!-- Our total_comments variable goes before the closing strong tag -->
                            {{ total_comments }}</strong>
                        {% endwith %}
                    </div>
                    <div class="col-1">
                        <a class="btn btn-outline-danger" href="{% url 'delete_post' post.id %}">Delete It</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col">
            <hr>
        </div>
    </div>
    <div class="row">
        <div class="col-md-8 card mb-4  mt-3 ">
            <h3 class="text-dark">Comments:</h3>
            <div class="card-body">
                <!-- We want a for loop inside the empty control tags to iterate through each comment in comments -->
                {% for comment in comments %}
                <div class="comments text-dark" style="padding: 10px;">
                    <p class="font-weight-bold">
                        <!-- The commenter's name goes here. Check the model if you're not sure what that is -->
                        {{ comment.name }}
                        <span class=" text-muted font-weight-normal">
                            <!-- The comment's created date goes here -->
                            {{ comment.created_on }}
                        </span> wrote:
                    </p>
                    <!-- The body of the comment goes before the | -->
                    {{ comment.body | linebreaks }}
                </div>
                <!-- Our for loop ends here -->
                {% endfor %}
            </div>
        </div>
        <div class="col-md-4 card mb-4  mt-3 ">
            <div class="card-body">
                <!-- For later -->
                {% if commented %}
                <div class="alert alert-success" role="alert">
                    Your comment is awaiting approval
                </div>
                {% else %}
                {% if user.is_authenticated %}

                <h3 class="text-dark">Leave a comment:</h3>
                <p class="text-dark">Posting as: {{ user.username }}</p>
                <form class="text-dark" method="post" style="margin-top: 1.3em;">
                    {{ comment_form | crispy }}
                    {% csrf_token %}
                    <button type="submit" class="btn btn-signup btn-lg">Submit</button>
                </form>
                {% endif %}
                {% endif %}
            </div>
        </div>
    </div>
</div>

{% endblock content %}

Any ideas?

Asked By: jakemcp97

||

Answers:

I think it should be model not form_class so:

class Deletepost(LoginRequiredMixin, DeleteView):
    model = Post
    success_url = reverse_lazy('blog:home')
    template_name = 'templates/post.html'

    def test_func(self):
        post = self.get_object()
        if self.request.user == post.author:
            return True
        return False
Answered By: Sunderam Dubey

@SunderamDubey’s answer is correct. The test_func will however not run, since this is method of the UserPassesTestMixin [Django-doc], not LoginRequiredMixin.

But using a test function as is done here is not efficient: it will fetch the same object twice from the database. You can simply restrict the queryset, like:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import DeleteView


class DeletePostView(LoginRequiredMixin, DeleteView):
    model = Post
    success_url = reverse_lazy('blog:home')
    template_name = 'templates/post.html'

    def get_queryset(self, *args, **kwargs):
        return (
            super().get_queryset(*args, **kwargs).filter(author=self.request.user)
        )

This will do filtering at the database side, and thus return a 404 in case the logged in user is not the author of the Post object you want to delete.

In the template, you will need to make a mini-form to make a POST request, for example:

<form method="post" action="{% url 'delete_post' post.id %}">
    {% csrf_token %}
    <button class="btn btn-outline-danger" type="submit">Delete</button>
</form>
Answered By: Willem Van Onsem

In my opinion, you should change url to below
‘path(‘delete/int:pk’, views.Deletepost.as_view(), name=’delete_post’),’

if didn’t work you can do this

def delete_post(request, post_id):
    post = Post.objects.get(pk=post_id)
    post.delete()
    return redirect('blog:home')
Answered By: Faez AR