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
Related
form.save() not working my form.save for updating data isnt working when i try to update my post it shows the original unedited post it dosent save the updated version.i donnt know whats causing the error idk if its views or anything in template if anyone could help i will be very grateful please help.
here is the code:
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponseRedirect
from .models import Post
from .forms import PostForm
def post_list(request):
posts = Post.objects.all()
context = {
'post_list': posts
}
return render(request, "posts/post_list.html", context)
def post_detail(request, post_id):
post = Post.objects.get(id=post_id)
context = {
'post': post
}
return render(request, "posts/post_detail.html", context)
def post_create(request):
form = PostForm(request.POST or None)
if form.is_valid():
form.save()
return HttpResponseRedirect('/posts')
context = {
"form": form,
"form_type": 'Create'
}
return render(request, "posts/post_create.html", context)
def post_update(request, post_id):
post = Post.objects.get(id=post_id)
form = PostForm(request.POST or None, instance=post)
if form.is_valid():
form.save()
return HttpResponseRedirect('/posts')
context = {
"form": form,
"form_type": 'Update'
}
return render(request, "posts/post_update.html", context)
def post_delete(request, post_id):
post = Post.objects.get(id=post_id)
post.delete()
return HttpResponseRedirect('/posts')
urls.py
from django.urls import path
from .views import post_list, post_detail, post_create, post_update, post_delete
urlpatterns = [
path('', post_list),
path('create/', post_create),
path('<post_id>/', post_detail),
path('<post_id>/update', post_update),
path('<post_id>/delete', post_delete),
]
post_update.html
<h1>welcome to post {{ form_type }}</h1>
<form method="POST" action=".">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button type="submit">{{ form_type }}</button>
</form>
action="." takes you from <post_id>/update to <post_id>/. You can fix this a few ways:
Change it to action="", which will submit from <post_id>/update to <post_id>/update.
Add a slash to the URL, i.e. path('<post_id>/update/', ...). Then action="." will submit from <post_id>/update/ to <post_id>/update/
Use the {% url %} tag instead of hardcoding the action. In your case there's a few changes you'd need to make, so I'll leave that as a challenge for you. The docs on reversing URLs should help.
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'.
I have a Django REST API server for my project. It uses built-in login system on http://127.0.0.1:8080/api-auth/login/.
I have additional Django project, that interacts with REST server and manages info from it. To view data, firstly I need to log in.
So I created a form in forms.py:
class LoginForm(forms.Form):
username = forms.CharField(label='username', max_length=50)
password = forms.CharField(widget=forms.PasswordInput())
And html template:
<form action="{% url 'todolist:login' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Login" />
</form>
And appropriate view in views.py:
class LoginView(View):
def get(self, request, *args, **kwargs):
form = LoginForm()
return render(request, 'login.html', {'form': form})
def post(self, request, *args, **kwargs):
form = LoginForm(request.POST)
if form.is_valid():
post_data = {'username': form.cleaned_data['username'], 'password': form.cleaned_data['password']}
response = requests.post('http://127.0.0.1:8080/api-auth/login/', data=post_data)
return HttpResponseRedirect('/todolists/')
But I get 403 Forbidden. What is a proper way to manage authorization?
django.middleware.csrf.get_token() is used for to get token internally, please add header with csrf token in python code and refer https://docs.djangoproject.com/en/1.11/ref/csrf/
In Views.py ,csrf_token is missing,so change your code like this,
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
class LoginView(View):
def get(self, request, *args, **kwargs):
form = LoginForm()
return render(request, 'login.html', {'form': form})
def post(self, request, *args, **kwargs):
form = LoginForm(request.POST)
if form.is_valid():
post_data = {'username': form.cleaned_data['username'],'password': form.cleaned_data['password']}
response = requests.post('http://127.0.0.1:8080/api-auth/login/', data=post_data)
return HttpResponseRedirect('/todolists/')
If you are django version above 1.7, #method_decorator should be used in django-api view.
Another way of doing ,is You can perform request to api with userdetails(username and password) as data in ajax using jquery and pass csrf-token value in header as csrf token can be get using
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
and in ajax success call you will get the response and redirect to new page as you mentioned in Views.py.It will load the content without refreshing page.
Hope it may helps!
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
Hello I wrote the code users to be able to edit the post when they want to. I could've done it successfully with delete, but for edit when the user clicks finalize edit button at the end, it won;t be edited.I have, http://127.0.0.1:8000/post/hello/ for hello post. Now for edit page http://127.0.0.1:8000/post/edit/hello/ .And lastly when user clicks finalize edit it should take me back to http://127.0.0.1:8000/post/hello/ with edited version. However it doesn't get edited.
views.py
class PostUpdateView(UpdateView):
model = Post
form_class = PostForm
template_name = 'main/edit.html'
def form_valid(self, form):
self.object = form.save(commit=False)
# Any manual settings go here
self.object.save()
return HttpResponseRedirect(self.object.get_absolute_url())
#method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
post = Post.objects.get(slug=kwargs['slug'])
if post.moderator == request.user:
return super(PostUpdateView, self).dispatch(request, *args, **kwargs)
else:
return http.HttpForbidden()
urls.py
url(r'^post/edit/(?P<slug>[\w|\-]+)/$', PostUpdateView.as_view(), name='post-edit'),
for edit.html
<form id="post_form" method="post" action="/post/{{ post.slug }}/" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
The form needs to submit to the edit page, so that the data can be processed and saved.