Search code examples
pythonpython-3.xdjangodjango-formsdjango-4.1

The view post.views.view didn't return an HttpResponse object. It returned None instead


I want to create a new post using PostCreateView and go to the details page of the new post in the next step, but I get this error:

(The view post.views.view didn't return an HttpResponse object. It returned None instead.)

views

class PostDetailView(View):
    """see detail post"""

    def get(self, request, post_id, post_slug):
        post = Post.objects.get(pk=post_id, slug=post_slug)
        return render(request, "post/detail.html", {"post": post})


class PostCreateView(LoginRequiredMixin, View):
    form_class = PostCreateUpdateForm

    def get(self, request, *args, **kwargs):
        form = self.form_class
        return render(request, "post/create.html", {"form": form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            new_post = form.save(commit=False)
            new_post.slug = slugify(form.cleaned_data["body"][:20])
            new_post.user = request.user
            new_post.save()
            messages.success(request, "you created a new post", "success")
            return redirect("post:post-detail", new_post.id, new_post.slug)

models

class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    body = models.TextField()
    slug = models.SlugField()
    img = models.ImageField(upload_to="%Y/%m/%d/")
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

urls

app_name = 'post'

urlpatterns = [
    path('', views.BlogView.as_view(), name="home"),
    path('detail/<int:post_id>/<slug:post_slug>/', views.PostDetailView.as_view(), name="post-detail"),
    path('delete/<int:post_id>/', views.PostDeleteView.as_view(), name="post-delete"),
    path('update/<int:post_id>/', views.PostUpdateView.as_view(), name="post-update"),
    path('create/', views.PostCreateView.as_view(), name="post-create"),
]


Solution

  • In case the form is not valid, you should rerender the template with the form, so:

    class PostCreateView(LoginRequiredMixin, View):
        form_class = PostCreateUpdateForm
    
        def get(self, request, *args, **kwargs):
            form = self.form_class
            return render(request, "post/create.html", {"form": form})
    
        def post(self, request, *args, **kwargs):
            form = self.form_class(request.POST)
            if form.is_valid():
                new_post = form.save(commit=False)
                new_post.slug = slugify(form.cleaned_data['body'][:20])
                new_post.user = request.user
                new_post.save()
                messages.success(request, 'you created a new post', 'success')
                return redirect('post:post-detail', new_post.id, new_post.slug)
            return render(request, 'post/create.html', {'form': form})

    But you are implementing a lot of boilerplate code here. What you here do is implementing a CreateView [Django-doc]:

    from django.contrib.messages.views import SuccessMessageMixin
    from django.views.generic import CreateView
    
    
    class PostCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
        form_class = PostCreateUpdateForm
        template_name = 'post/create.html'
        success_message = 'you created a new post'
    
        def form_valid(self, form):
            form.instance.slug = slugify(form.cleaned_data['body'][:20])
            form.instance.user = request.user
            return super().form_valid()
    
        def get_success_url(self):
            return reverse('post:post-detail', args=(new_post.id, new_post.slug))