Method Not Allowed (POST): /home/ - python

I have a one page app with a form and a data table. The page load fine, but the problem is the Form is not working when I press the "SUBMIT" Button.
When I press the "SUBMIT" Button it give me this error Method Not Allowed (POST): /home/
Thanks you for the help guys!
views.py
def _get_form(request, formcls, prefix):
data = request.POST if prefix in request.POST else None
return formcls(data, prefix=prefix)
all_items = List.objects.all
class Myview(TemplateView):
template_name = 'data_list/home.html'
all_items = List.objects.all
def get(self, request, *args, **kwargs):
return self.render_to_response({'scrape': Scrape(prefix="scrape_pre"), 'all_items': all_items})
def scrape(self, request, *args, **kwargs):
scrape = _get_form(request, Scrape, 'scrape_pre')
if request.method == "POST":
scrape = _get_form(request, Scrape, 'scrape_pre')
if scrape.is_valid():
print("Worked")
return self.render_to_response({'scrape': scrape})
def home(self, request, *args, **kwargs):
all_items = List.objects.all
return render(request, "data_list/home.html", {"all_items": all_items})
forms.py
class Scrape(forms.ModelForm):
url = forms.CharField()
class Meta:
model = List
fields = ["item", "site"]
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path("", views.add, name="add"),
path("scrape/", views.scrape, name="scrape"),
path("home/", views.Myview.as_view(), name="home"),
path("delete/<list_id>", views.delete, name="delete"),
path("datacontent/<list_id>", views.datacontent, name="datacontent")
]
home.html
<div>
<form action="" method="post" >
{% csrf_token %}
{{ scrape|crispy }}
<pre></pre>
<button class="btn btn-outline-info" type="submit" value="Submit">SUBMIT</button>
<pre></pre><pre></pre><pre></pre><pre></pre>
</form>
</div>
<table class="table">
.....

You can't send a post request (method='post' in the form definition) if your backend doesn't implement the post function, which is responsible for responding the post requests. You should change your 'scrape' function to 'post'.

Related

Django DeleteView not make delete

I want to convert user deletion from FBV to CBV
My FBV
def delete_student(request, pk):
student = get_object_or_404(Student, pk=pk)
student.delete()
return HttpResponseRedirect(reverse("students:get_students"))
My CBV
class DeleteStudentView(DeleteView):
model = Student
form_class = StudentForm
template_name = "students/students_list.html"
success_url = reverse_lazy("students:get_students")
student_list.html
<td><a type="button" class="btn btn-danger"
href="{% url 'students:delete_student' student.pk %}">Delete</a>
</td>
There is no error, but no selection occurs. What could be the problem?
A DeleteView deletes with a POST or DELETE request. This is mandatory by the specs of the HTTP protocol. Your FBV is not HTTP compliant.
You thus will need to make a mini-form to do this. For example make a hidden form with:
<td><button class="btn btn-danger" onclick="delete_item({{ student.pk }});">Delete</button></td>
<!-- … -->
<form method="post" action="{% url 'students:delete_student' %}" id="delete_form">
{% csrf_token %}
<input type="hidden" name="pk" id="delete_pk">
</form>
<script>
function delete_item(pk) {
var hidden_item = document.getElementById("delete_pk");
hidden_item.value = pk;
var form = document.getElementById("delete_form");
form.submit();
}
</script>
In the urls.py we define an entry for the StudentDeleteView without parameters:
# students/urls.py
from django.urls import path
app_name = 'students'
urlpatterns = [
# …
path('student/delete/', StudentDeleteView.as_view(), 'delete_student'),
# …
]
In the DeleteView, you then determine the object with the primary key:
from django.shortcuts import get_object_or_404
class DeleteStudentView(DeleteView):
model = Student
success_url = reverse_lazy('students:get_students')
def get_object(self, *args, **kwargs):
return get_object_or_404(Student, pk=self.request.POST.get('pk'))
To make your function-based view HTTP compliant, you should enforce that it can only do this with a POST or DELETE request, for example with a #require_http_methods(…) decorator [Django-doc]:
from django.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_http_methods
#require_http_methods(["DELETE", "POST"])
def delete_student(request):
student = get_object_or_404(Student, pk=request.POST.get('pk'))
student.delete()
return redirect('students:get_students')
and thus use the same "trick" with the mini-form.

Trouble getting a Django Form to render

Wondered if someone could help me with what I am doing wrong.
I wish to present an order form in Django where a customer will only ever fill in an order, they will never need to retrieve an existing order. So I think I only need a POST method and no GET method.
When I try to render a url with a form, I get a 405 response.
In my views.py file where I think I am making a mistake I have:
class RequestReport(View):
def post(self, request, *args, **kwargs):
form = CustomerOrderForm(data=request.POST)
if form.is_valid():
form.save()
return render(
"order.html",
{
"form": CustomerOrderForm()
}
)
And in my app urls file I have:
urlpatterns = [
path('', views.RequestHome.as_view(), name='home'),
path('order', views.RequestReport.as_view(), name='order'),
path('blog', views.RequestBlog.as_view(), name='blog'),
path('<slug:slug>/', views.PostDetail.as_view(), name='post-detail'),
]
And finally in my order.html file I have:
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" class="report-buttons">
</form>
I know that the Customer Order Form is fine because if I insert this in my view it renders correctly
class RequestReport(CreateView):
form_class = CustomerOrderForm
template_name = 'order.html'
success_url = "about"
But I want to be able to post the form.
405 is a Method Not Allowed error. Since you are making a get request when you go to /order, and your view hasn't implemented a get method, it results in a 405 error.
class RequestReport(View):
def post(self, request, *args, **kwargs):
form = CustomerOrderForm(data=request.POST)
if form.is_valid():
form.save()
return redirect("somewhere else")
def get(self, request, *args, **kwargs):
return render(
request,
"order.html",
{
"form": CustomerOrderForm()
}
)
You still need to reach the form i.e. to "go" to the url where this form is without submitting it so that would be the get request

success url does not work in my class based DeleteView

My success_url for my class based delete view does not work for some reason.
in views.py
# allows a user to delete a project
class DeletePost(DeleteView):
template_name = 'user_posts/post_delete.html'
model = Post
# return to the all posts list
success_url = reverse_lazy('posts_list')
# make sure the user is looking at its own post
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if not obj.user == self.request.user:
raise Http404("You are not allowed to Delete this Post")
return super(DeletePost, self).dispatch(request, *args, **kwargs)
in urls.py:
path('list/', PostsListView.as_view(), name="posts_list"),
path('create-post/', CreatePostView.as_view(), name="post_create"),
path('update-post/<int:pk>', UpdatePost.as_view(), name="post_update" ),
path('delete-post/<int:pk>', DeletePost.as_view(), name="post_delete")
in the HTML file:
{% extends 'base.html' %}
{% block content %}
<form action="." method="POST" style="width:80%;">
{% csrf_token %}
<h3>Do You want to delete this post: "{{ object.title }}"</h3>
<input class="btn btn-primary" type="submit" value="Confirm"/>
Cancel
</form>
{% endblock content %}
whenever I click ok to delete a specific project, it doesn't return to the list of posts for:
image of the error on the webpage
you have not this URL indeed:
forum-posts/delete-post/
actually, you forgot to specify an integer indicating the post_id that must be deleted. for example:
forum-posts/delete-post/1/

Django - Comment form in an existing template. How to define it in views.py?

I have 4 models: Post, Comment, Blogger and User.
I have an post_description template, in below of that, I have placed a comment form.
But how to define it in views? My problem is - to get its username, like the user who is logged in will be stored as "posted_by" and in which blog post he post will be stored as "topic" of the blog.
How to store these information, so they get automatically added?
Form that i has described in post_desc.html
{% if user.is_authenticated %}
<form method="post">
{% csrf_token %}
<input type="text" name="comment" style="width: 800px; height: 145px;">
<button type="submit">Submit Comment</button>
</form>
{% else %}
<p>Login to comment</p>
{% endif %}
Current view of that post_desc:
def post_desc(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'post_desc.html', {'post': post})
Now the user can be accessed as follows in the views:
user = request.user
And about the Topic, maybe you could add a hidden input in your form to get blog id , as you are already passing the post in the form template. :
<form method="post">
{% csrf_token %}
<input type="text" name="comment" style="width: 800px; height: 145px;">
<input type="hidden" name="topic" value="{{ post.id }}">
<button type="submit">Submit Comment</button>
And when posted in the view you can get blog by:
post_id = request.POST.get('topic')
post = get_object_or_404(Post, pk=post_id)
And then finally proceeding with your actual flow.
I think what you need here is basic model form setup.
I am hoping there is a blog entry and comments associated with it and you want a commenting functionality on each post.
This is rough quick answer.
Your models.py looks like this:
from django.db import models
from django.conf import settings
class Comments(models.Model):
posted_by = models.ForeignKey(settings.AUTH_USER_MODEL)
topic = models.ForeignKey(Blog)
comment = models.TextField()
last_modified = models.DateTimeField(auto_now=True)
created_on = models.DateTimeField(auto_now_add=True)
You setup a model form in your forms.py
from django.forms import ModelForm
from .models import Comments
class CommentForm(ModelForm):
class Meta:
model = Comments
fields = ['comment']
You setup a model form post view.
#login_required
#require_http_methods(["POST"])
def post_comments_controller(request, identifier):
from .forms import CommentForm
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
comment_obj = comment_form.save(commit=False)
topic = Blog.objects.get(id=identifier)
comment_obj.posted_by = request.user
comment_obj.item = topic
comment_obj.save()
return HttpResponse("Done")
else:
return HttpResponseBadRequest()
You setup a entry point in your urls.py
from django.conf.urls import patterns, url
from django.conf import settings
urlpatterns = patterns('',
url(r'^/blog/(?P<identifier>[d]+)/comment$',
'views.post_comments_controller', name='post_comment')
)
And your finally the html form
{% if user.is_authenticated %}
<form method="POST" action="{% url 'post_comment' blog.id %}">
{% csrf_token %}
<input type="text" name="comment" style="width: 800px; height: 145px;">
<button type="submit">Submit Comment</button>
</form>
{% else %}
<p>Login to comment</p>
{% endif %}
This is not tested overall. Let me know.
From Django docs you can use FormMixin with DetailView like this:
class AuthorInterestForm(forms.Form):
message = forms.CharField()
class AuthorDetail(FormMixin, DetailView):
model = Author
form_class = AuthorInterestForm
def get_success_url(self):
return reverse('author-detail', kwargs={'pk': self.object.pk})
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
# Here, we would record the user's interest using the message
# passed in form.cleaned_data['message']
return super().form_valid(form)

Django: How to use request.POST in a delete view

I have a form sending data to a view via POST method. My problem is that I cant access the form's post data in the deleteview. After the song is deleted, I want the user to be sent back to the album-detail page to which the song belongs. My code is as shown below:
The form (inside album_detail.html):
<form action="{% url 'music:delete-song' pk=song.pk album_id=song.album_id %}" method="POST">
{% csrf_token %}
<input type="hidden" name="album_id" value="{{ song.album_id }}" />
<button type="submit" class="btn btn-danger btn-xs" role="button">Delete</button>
</form>
The urls.py:
#----
app_name = 'music'
urlpatterns = [
#----
url(r'^album/(?P<pk>[0-9]+)/detail/$', views.AlbumDetail.as_view(), name='album-detail'),
url(r'^song/(?P<pk>[0-9]+)/delete/(?P<album_id>[0-9]+)/$', views.SongDelete.as_view(), name='delete-song'),
]
And finally the view:
class SongDelete(DeleteView):
model = Song
album_id = request.POST.get('album_id')
success_url = reverse_lazy('music:album-detail', kwargs={'pk': album_id})
The album_id can not be set as above. How can I set the album_id to the post data album_id from the form, so that the user is sent back to the album-detail URL?
By implementing your views get_success_url of course:
def get_success_url(self):
album_id = self.request.POST.get('album_id') # Do something else if it's missing?
return reverse( # no need for lazy here
'music:album-detail',
kwargs={'pk': album_id}
)
You Have to override delete() and get_success_url()
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.album = self.object.album # assuming that song have a foreignkey reference to album model
self.object.delete()
success_url = self.get_success_url()
return HttpResponseRedirect(success_url)
def get_success_url(self):
album = self.album
return reverse(
'music:album-detail',
kwargs={'pk': album.id}
)
success_url is obtained from get_success_url() method and that method is called from delete(). Instead of calling reverse you can do something like
def get_success_url(self):
return `/album/details/' + str(self.album.id)
To make it simpler. Or you can directory provide redirect_url in delete method.
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.album = self.object.album # assuming that song have a foreignkey reference to album model
self.object.delete()
return HttpResponseRedirect('/album/details/' + str(self.album.id))
Refer to this link to get help on class based views

Categories

Resources