Django form_valid not passing params to CreateView

Question:

In my django project, I’m trying create a ‘submit post’ page using CreateView. It works, but with a dropdown menu for the author of the post. I would like to have the author automatically added to the post.

According to the (documentation)[https://docs.djangoproject.com/en/4.1/topics/class-based-views/generic-editing/], I should use a form_valid method to add the author to the form. This does not work, even though it’s copied directly from the documentation.

I’ve tried adding 'author' to the fields in the PostCreate class, and that only adds the author dropdown box to the form.

Views.py:

class PostCreate(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['image', 'description']
    success_url = '/'
    template_name: 'post_form.html'

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

changing to self.author = self.request.user.pk does not work, either.

Models.py:

class Post(models.Model):
    image = models.ImageField()
    description = models.TextField(null=True )
    author = models.ForeignKey(User, on_delete=models.CASCADE)

when looking at the debug error, I can see the author param is not passed, resulting in a NOT NULL constraint failed.

It seems to be the problem is with this line:

    def form_valid(self, form):
        self.author = self.request.user  ## The problem should be here
        return super().form_valid(form)

I’ve changed this line to the following, with no success:

  • form.instance.author = self.request.user
  • form.instance.user = self.request.user
  • self.author = self.request.user
  • self.author = self.author.user.pk

In all of these changes, the traceback always passes None to the params. This leads me to believe there is something wrong on another line.

Here is the 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
from posts.views import PostList, PostCreate, PostDetail, Profile
from django.urls import reverse, re_path



urlpatterns = [
    path('admin/', admin.site.urls),
    path("accounts/", include("accounts.urls")),
    path('accounts/', include('django.contrib.auth.urls')),
    path('', PostList.as_view(), name='list'),
    path('new/', PostCreate.as_view(), name='new'),
    path('posts/<pk>/', PostDetail.as_view(), name='detail'),
    path('<str:username>/', Profile.as_view(), name='user_profile'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Asked By: Shelly Bysshe

||

Answers:

Write form.instance.author=self.request.user as form contains all the instances after validation of form, so:

class PostCreate(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['image', 'description']
    success_url = '/'
    template_name='post_form.html'

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

Note: class based views require their name to be written as model name as prefix and actual view name as the suffix, so you may it to PostCreateView from PostCreate.

Edit:

I see a big mistake it should be template_name='post_form.html, you have used : instead of =.

Answered By: Sunderam Dubey