Saving posts without creating URL routes

Hello, I need some help with the blog. In my project I have the Post model and the PostForm for the author for adding new posts. Post model has status field with choices “PUB”, “TO-PUB” and “DRAFT” and when the author choose “DRAFT” or “TO-PUB” status I want to save the post in the database but without creating a corresponding URL route and display, after submit I just want to redirect the user to the homepage.

I use Class-Based Views. Right now I tried to achieve this by modify ‘dispatch’ in PostDetailView:

class PostDetailView(DetailView):
    model = Post

    def dispatch(self, request, *args, **kwargs):
        post_obj = self.get_object()
        if not post_obj.status == 'PUB':
            return redirect(reverse('app_reviews:home'))
        return super().dispatch(request,*args,**kwargs)

But in this scenario the new post is still creating in the corresponding URL, only redirect works correctly.

My second idea was to modify CreateView:

class PostCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
    model = Post
    form_class = PostForm
    permission_required = 'app_reviews.add_post'
    permission_denied_message = "You don't have permission to access this page. Please log in using a valid account"
    template_name = 'reviews/post_add.html'

    def form_valid(self, form):
        form.instance.author = self.request.user
        if form.instance.status == 'PUB':
            return super().form_valid(form)
        return redirect(reverse('app_reviews:home'))

But here I have another problem that posts without “PUB” status aren’t even created and saved in database…

What can I do?

Can you be more specific and provide more details about what you mean by this? I’m not following what you’re trying to describe here.

Apologies for any confusion. I meant when I implemented the dispatch function, posts without ‘PUB’ status are being saved in database and I am redirected to the homepage but the problem is that the URL for that post is connected with redirect home permanently. For instance, if an author creates a post with the ‘review’ title and a ‘DRAFT’ status and submits, when I try to open site ‘./review’ in the browser I am redirecting to the homepage what is wrong because that site should give me an error (404?) that it doesn’t exist.

What is your url definition for review?

path('<slug:slug>/', PostDetailView.as_view(), name='review')

What is your url definition for your homepage?

What you posted here was for the name attribute review.

What is your url assignment for the url path review.

I don’t have assignment for the review path, it was just an example for creating a new post using PostDetailView which creates the url path automatically for me.


This is my entire urls.py file containing the homepage:
from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView

app_name = 'app_reviews'

urlpatterns = [
    path('', PostListView.as_view(), name='home'),
    path('add-review/', PostCreateView.as_view(), name='add_review'),
    path('<slug:slug>/', PostDetailView.as_view(), name='review'),

I use the name 'review' because all the posts will be product reviews.

Ok, the picture has become clearer here.

You have:

This will call PostDetailView for any single-parameter url supplied.

Then, in your view you have:

So you have an entry by whatever name you’ve previously submitted, but I’m guessing its status in not ‘PUB’, in which case the if will be True and the view will redirect you to home.

The description you’ve supplied then appears to be accurate based upon the code posted.

No 404 will be generated because get_object is going to return the object related to the supplied slug.

Hi. As far as I can understand, you want:

  • The PostDetailView to only allow display of Posts with a PUB status, and raise a 404 for posts with another status

  • The PostCreateView to always save the post in database (which is not the case in your second idea example for non-PUB posts because you do not call super().form_valid() for such cases) but redirect to the PostDetailView for PUB posts (which is likely to be the default behaviour of super().form_valid() because you provide, I guess, a get_absolute_url() method on your Post model) and redirect to home page for non-PUB posts (to avoid the 404 if redirecting to PostDetailView for them)

If I’m correct in my assumption, then you should implement your views as follow:

class PostDetailView(DetailView):
    queryset = Post.objects.filter(status="PUB")
class PostCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
    model = Post
    form_class = PostForm
    permission_required = 'app_reviews.add_post'
    permission_denied_message = "You don't have permission to access this page. Please log in using a valid account"
    template_name = 'reviews/post_add.html'

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

    def get_success_url(self):
        # This is called by form_valid which set self.object with the saved Post instance
        if self.object.status == "PUB":
            return super().get_success_url()  # normal behaviour
        return reverse('app_reviews:home')
1 Like

Yes, you’ve described exactly what I wanted to achieve and your code works perfectly for me. Thank you so much. Now it’s time to analyze it and keep learning.