简体   繁体   中英

Django: WARNING - Method Not Allowed (POST)

I know what above error means. Seems I can't handle form when it is posted. I can do it in function based views, but in class based views I am tad lost.

I am creating a comment app and here is forms.py content in comment app:

class CommentForm(forms.Form):
    content_type = forms.CharField(widget=forms.HiddenInput)
    object_id = forms.CharField(widget=forms.HiddenInput)
    body = forms.CharField(widget=forms.Textarea)

then in DetailView of the blog app, I handled it this way:

class BlogDetail(DetailView):
    model = Blog
    template_name = 'blogs/blog_detail.html'
    context_object_name = 'blog'

    def get_object(self):
        blog_slug = self.kwargs.get('blog_slug')
        return get_object_or_404(Blog, slug=blog_slug)

    def get_context_data(self, *args, **kwargs):
        obj = self.get_object()
        context = super().get_context_data(**kwargs)
        context['comments'] = Comment.objects.filter_by_instance(obj)

        """ comment form """
        initial_data = {
            'content_type': obj.get_content_type,
            'object_id': obj.id
        }
        if self.request.method == 'POST':
            form = CommentForm(self.request.POST, initial=initial_data)
            if form.is_valid():
                c_type = form.cleaned_data.get('content_type')
                content_type = ContentType.objects.get(model=c_type)
                object_id = form.cleaned_data.get('object_id')
                body = form.cleaned_data.get('body')
                new_comment, created = Comment.objects.get_or_create(
                    user=self.request.user,
                    content_type=content_type,
                    object_id=object_id,
                    body=body
                )
        else: 
            form = CommentForm(initial=initial_data)

        context['comment_form'] = form

        return context

albeit I passsed form = CommentForm(self.request.POST, initial=initial_data) but there sounds something is going wrong, Can anyone help? Thank you

edited:

class BlogDetail(DetailView, FormView):
    model = Blog
    template_name = 'blogs/blog_detail.html'
    context_object_name = 'blog'
    form_class = CommentForm

    def get_object(self):
        blog_slug = self.kwargs.get('blog_slug')
        return get_object_or_404(Blog, slug=blog_slug)

    def get_initial(self):
        obj = self.get_object()
        return {
            'content_type': obj.get_content_type,
            'object_id': obj.id
        }

    def form_valid(self, form):
        c_type = form.cleaned_data.get('content_type')
        content_type = ContentType.objects.get(model=c_type)
        object_id = form.cleaned_data.get('object_id')
        body = form.cleaned_data.get('body')

        Comment.objects.create(
            user=self.request.user,
            content_type=content_type,
            object_id=object_id,
            body=body
        )

edit 2:

Can anyone spot the error with this approach:

class BlogDetail(DetailView):
    model = Blog
    template_name = 'blogs/blog_detail.html'
    context_object_name = 'blog'
    form_class = CommentForm

    def get_object(self):
        blog_slug = self.kwargs.get('blog_slug')
        return get_object_or_404(Blog, slug=blog_slug)

    def get(self, request, *args, **kwargs):
        obj = self.get_object()

        initial_data = {
            'content_type': obj.get_content_type,
            'object_id': obj.id
        }
        print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", obj.get_content_type)
        form = self.form_class(initial=initial_data)

        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)

        if form.is_valid():
            c_type = form.cleaned_data.get('content_type')
            content_type_2 = ContentType.objects.get(model=c_type)
            object_id = form.cleaned_data.get('object_id')
            body = form.cleaned_data.get('body')

            Comment.objects.create(
                user=request.user,
                content_type=content_type_2,
                object_id=object_id,
                body=body,
            )

        return render(request, self.template_name, {'form': form})

Posts are handled by the post method of the class-based view:

class BlogDetail(DetailView):
    # ...
    def post(self, request, *args, **kwargs):
        # all your form processing

Django ships with several views, that already provide various hooks into the form handling process, eg FormView , that you could leverage instead:

class BlogDetail(DetailView, FormView):
    form_class = CommentForm

    def form_valid(self, form):
        c_type = form.cleaned_data.get('content_type')
        # ...

    def get_initial(self):
        obj = self.get_object()
        return {
            'content_type': obj.get_content_type,
            'object_id': obj.id
        }

    # ....

By default, the form is passed as "form" into the context.

To allow post requests to your view, write a function def post(self, request, *args, **kwargs) which will receive the post request. If you want to handle this as you would handle get, redirect it to the get function

def post(self, request, *args, **kwargs):
    return self.get(request, *args, **kwargs)

You don't need the DetailView . You can simply use CreateView. I think you have everything overridden correctly to be able to ditch DetailView, except maybe get_form_kwargs().

However...

I usually approach this differently, cause it's confusing and very hacky. Instead, you add the form via get_context_data() to the DetailView and then in the template post to /blog/{id}/comment/create , where you have the CreateView. That makes things a lot simpler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM