So i'm not even sure how to search for someone who had the same thing happen to them.
I'm working on a django website and my form won't post to my database, instead, i get redirected to a URL containing the information that was in the forms, like this:
<form id="form">
<input type="hidden" id="compinp" name="compinp">
<input maxlength="20" onkeyup="showpost()" name="title" id="titleinput">
{{ captcha }}
</form>
Where compinp is some other data that gets posted, {{ captcha }} is a reCaptcha checkbox that works just fine, and when everything is filled in and getting posted, instead of running the post function from views.py, instead i get redirected to this:
http://localhost:8000/newentry/?compinp=XXXX&title=XXXX&g-recaptcha-response="xxxx-xxxx-xxxx"
It gets posted via jQuery through a button outside of the form, though i tried to add a submit button inside it and got the exact same thing.
The views.py function that handles that looks like this:
def newentry(request):
if request.method == "GET" and request.user.is_authenticated():
#creating objects for the view, works fine too
return render(request, "newentry.html",
{"champlist": complist, "captcha": captcha})
elif request.method == "POST" and request.user.is_authenticated():
captcha = Captcha(request.POST)
title = request.POST.get("title", False)
compname = request.POST.get("compinp", False)
comp = Comp.objects.get(title=compname)
if captcha.is_valid() and title and compname:
newe= entry_generator(request.user, title, comp)
newe.save()
return redirect('/')
else:
return redirect('/')
else:
handle_home(request.method, request.user)
This view tries to post models from another app in the same project, if that makes it any different.
I had added a print attempt at the right after the request check for post it didn't print anything.
Not sure what other info i can give to help, if you want any, just ask (:
You need to add the form method post:
<form id="form" method="post">
<input type="hidden" id="compinp" name="compinp">
<input maxlength="20" onkeyup="showpost()" name="title" id="titleinput">
{{ captcha }}
</form>
Related
I'm doing a simple shopping website with a order confirmation page but I'm finding that there are duplicate POST requests to my /confim-order route. I have a home page that redirects on POST:
#views.route('/', methods=['GET', 'POST'])
#login_required
def home():
if request.method == 'POST':
# save information from the form for later use
session['text'] = request.form.get('samples')
session['note'] = request.form.get('note')
return redirect(url_for('views.confirm_order'))
return render_template("home.html", user=current_user)
My order confirmation function:
#views.route('/confirm-order', methods=['GET', 'POST'])
#login_required
def confirm_order():
if request.method == 'POST':
text = session['text']
note = session['note']
session.pop('text', None)
session.pop('note', None)
create_order(current_user, text, note)
return redirect(url_for('views.home'))
elif request.method == 'GET':
text = session['text']
note = session['note']
sample_list = get_samples(text, note)
return render_template("confirm.html", user=current_user, sample_list=sample_list)
There's no JavaScript in the HTML template. What's in confirm.html is essentially:
<form method="POST">
<div class="form-group">
<label for="cc">Credit Card</label>
<input type="text" class="form-control" id="cc" name="cc" placeholder="Credit Card Number" />
</div>
Click button to place order:
<p></p>
<div align="right">
<button type="submit" id="submit_btn" class="btn btn-success">Place Order</button>
</div>
</form>
This is what I see: sometimes, clicking submit works fine. Most times clicking submit results in two POST requests to confirm_order() and then I get a "This site can’t be reached" message in my browser at http://localhost:5000/confirm-order. I've been at this for almost an entire day. I put some print statements that seem to suggest the first POST to /confirm-order is initiated correctly from the template rendered we reach /confirm-order by GET from home: /. The second POST to /confirm-order came immediately after first the POST from within POST of /confirm-order. When that happens, I get the "This site can't be reached" message and I find that duplicate orders have been created.
I've searched online and most people that have duplicate POST issues are using JavaScript along with the form submission button. But my page doesn't use Javascript. If someone sees what's wrong, any help is greatly appreciated. Thank you.
EDIT: Here's the create_order() function in case something in there is causing the problem:
def create_order(user, text, note):
new_order = Order(user_id=current_user.id, text=text,
status='submitted', note=note)
db.session.add(new_order)
db.session.commit()
I'm not 100% sure this is the issue but it's the most likely thing I can think of.
I think there are some issues in your html since you don't specify the url for action. I would also use an input tag rather than button for submit.
More generally, I would also recommend following a few of the things mentioned here. So use the data in request.form rather than in the session object since you can control and validate that more explicitly within Flask (for instance if this is going into production you may want to implement WTF Forms for security reasons to prevent CSRF).
<form action="/confirm-order" method="post">
<div class="form-group">
<label for="po">Purchase Order</label>
<div class="form-group">
<label for="cc">Credit Card</label>
<input type="text" class="form-control" id="cc" name="cc" placeholder="Credit Card Number" />
</div>
Click button to place order:
<p></p>
<div align="right">
<input type="submit" id="submit_btn" class="btn btn-success">Place Order</input>
</div>
</form>
Little general explanation.
I'm pretty newbie in Django, I have a little knowledge, but nothing as experience. The code that I want ask about is working, but I have a question about good/bad practice. Does my approach is good or at least not bad?
Little use case explanation.
I have a site with the items. There is a functionality to add the items and now I want to add a possibility to delete the item.
Use case : on the page of item user clicks on the button Delete, we will show a page with details about this item and the button "Confirm delete" at the bottom. If user click on the button I delete this item from database.
So
I create in urls.py
path('item/delete/<int:id>/', views.delete_item, {}, 'delete_item'),
I create in views.py
def delete_item(request,id):
if id :
cur_item = get_object_or_404(Item, pk=id)
else :
raise Http404
if request.POST:
try :
post_item_id=int(request.POST["pk"])
except ValueError :
messages.error(request,"Wrong id number")
return render(request, 'myapp/item_delete_form.html', {'cur_item': cur_item})
if (request.POST["delete"] == "yes") and (post_item_id == id):
Item.objects.filter(pk=id).delete()
# Delete was successful, so redirect to another page
redirect_url = reverse('items')
return redirect(redirect_url)
else:
messages.error(request, "id number in form not the same as in URL")
return render(request, 'myapp/item_delete_form.html', {'cur_item' : cur_item})
return render(request, 'myapp/item_delete_form.html', {'cur_item' : cur_item})
I do not use Django Forms as for me it's not the real Django form (i.e. it's not linked to a Model). As mention by #akx in the comments I could always create a Form based directly on forms.Form. But it seems also useless for me as in fact there is almost no data in my form.
Instead I just create generic form in the template.
In templates/myapp/item_delete_form.html
First part of template get cur_item and show it. And then :
<form method="post">
{% csrf_token %}
<input type="hidden" value="{{ cur_item.id }}" name="pk">
<input class="btn btn-default btn-danger" name="delete" type="submit" value="yes"/>
</form>
Finally here the small test to check it :
def test_delete_item(self):
test_serial = "111-111"
new_item = Item(serial_number=test_serial)
new_item.save()
url = reverse("delete_item", kwargs={'id':new_item.id})
resp = self.client.get(url)
confirm_data = {'pk': new_item.id,'delete': 'yes'}
resp = self.client.post(url, confirm_data)
self.assertEqual(Item.objects.all().count(), 0)
Whilst I'll be very appreciate to have and comments about my realisation, here are some practical questions.
Does the practice to analyze request.POST list is not the "bad practice"?
As I do not use Django forms I could not do form.is_valid. Is it ok?
Are there some pitfalls that I should think about (for example does user have the rights to delete this item, but for the moment user system is not developed so I could do nothing about that)?
Does my test is relevant?
And finally, if my realization is not a good or acceptable practice, how should I do my use case ?
You can save yourself quite some trouble by just using Django's default DeleteView CBV:
urls.py
path('item/delete/<int:pk>/', DeleteItemView.as_view(), name='delete_item'),
views.py
class DeleteItemView(DeleteView):
model = Item
template_name = "myapp/item_delete_form.html"
success_url = reverse_lazy('items')
item_delete_form.html
<form method="post">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="yes" />
</form>
In fact, you don't even necessarily need a views.py. Just setting the arguments for the CBV in urls.py would do...
path(
"item/delete/<int:pk>/",
DeleteView.as_view(
model=Item,
template_name="myapp/item_delete_form.html",
success_url=reverse_lazy("items"),
),
name="delete_item",
)
would be equivalent.
i want to delete a task from the database so i use this code
this is my delete view
def task_Delete(request,id=None):
if request.method == 'POST':
form = TaskForm()
id = int(request.POST.get('task.id'))
task = Task.objects.get(id=id)
task.delete()
messages.success(request,"successfully delete")
return render_to_response('home.html', {'form': form})
and that is my urls.py
url(r'^task_Delete/$', views.task_Delete, name='task_Delete')
this the code of the button delete :
<form action="{% url 'task_Delete' %}" method="post" >
{% csrf_token %}
<input type="hidden" name="task_id" value="{{task.id}}" />
<input type="submit" value="delete task">
</form></td>
</tr>
when i click on delete nothing happend i don't know why , please help thanks in advance
There are various problems in your code (for example the TaskForm is not needed at all) however if you change the line
id = int(request.POST.get('task.id'))
to
id = int(request.POST.get('task_id'))
the object will probably be deleted; remember that the request parameter's name will be the same as the name of the input (task_id). I recommend using proper CBVs (a DeleteView) for what you want to do - if you want a slow and comprehensive tutorial on that I recommend this article: https://spapas.github.io/2018/03/19/comprehensive-django-cbv-guide/
I'm learning django, in this moment I'm trying to implement web forms, actually some of them works fine with the data base model but I'm trying to make a new one without use the models. The problem is that django show me the token and not the value typed in the form.
I hope you can help me, to understand more about it.
URLS:
url(r'^test', views.test),
VIEWS:
def test(request):
if request.method == "POST":
return HttpResponse(request.POST)
return render(request, 'datos.html')
DATOS HTML:
<form action="/test" method="post" name="myForm"> {% csrf_token %}
<input type="text">
<input type="submit">
</form>
When I run this django show me:
csrfmiddlewaretoken
Can any one help me please?
To protect from Cross-Site_Request_Forgery attack, for each post request we need to send a csrf token, from the form, which is missing in your form, you can get rid of this error by modifying your form as follows.
<form action="/test" method="POST" name="myForm">
{% csrf_token %}
<input type="text">
<input type="submit">
</form>
and You need to get the data from your views,
def test(request):
if request.method == "POST":
# Getting the value of text field from the form
# If the value is empty set the default value to None
text = request.POST.get('text', None)
# Do not return the POST request
# Return the value you get from the form
return HttpResponse(text)
# This code is not going to execute
# Return is already encountered above in our code
return render(request, 'datos.html')
# To send data to form do,
# return render(request, 'datos.html', {'my_data': text})
I have django 1.4 and I am following a tutorial which uses an older version of django. Its a simple tutorial which creates a wiki app with Page as model.
The problem is that the view function corresponding to a POST method in a form is not getting invoked.
This is the content in the urls.py:
url(r'^wikicamp/(?P<page_name>[^/]+)/edit/$', 'wiki.views.edit_page'),
url(r'^wikicamp/(?P<page_name>[^/]+)/save/$', 'wiki.views.save_page'),
url(r'^wikicamp/(?P<page_name>[^/]+)/$', 'wiki.views.view_page'),
This is the content of the template edit.html:
<from method = "get" action="/wikicamp/{{page_name}}/save/">
{% csrf_token %}
<textarea name = "content" rows="20" cols="60">
{{content}}
</textarea>
<br/>
<input type="submit" value="Save Page"/>
</form>
this is link to save
And this is the content in views.py:
def edit_page(request, page_name):
try:
page = Page.objects.get(pk=page_name)
content = page.content
except Page.DoesNotExist:
content = ""
return render_to_response("edit.html", {"page_name":page_name, "content":content}, context_instance=RequestContext(request))
def save_page(request, page_name):
return HttpResponse("You're looking at the page %s." % page_name)
I initially I was getting csrf related error and I then tried all the fixes provided in https://docs.djangoproject.com/en/dev/ref/contrib/casrf/ and followed many many stackoverflow question related to POST and django. Now nothing happens when I click the 'Save Page' button, nothing! Not even any request being sent from the form (Using firebug to track the HTTP request and response)
You have a typo in your HTML: from instead of form.
You may realize this, but that code won't really save anything. I'm not sure what blog you are following, but you would be better-off following the official Django tutorial in the documentation, then reading the forms docs.
You may need to change method to "POST" in your form.
<from method = "get" action="/wikicamp/{{page_name}}/save/">
to
<form method = "post" action="/wikicamp/{{page_name}}/save/">
There are some spelling mistakes, such as from instead of form.
Also the form is malformed.
Change:
this is link to save
to
<input type="submit" value="Save Page" />
And thirdly, change the method= "get"to method="POST".
The entire form should look like this
<form method = "POST" action="/wikicamp/{{page_name}}/save/">
{% csrf_token %}
<textarea name = "content" rows="20" cols="60">
{{content}}
</textarea>
<br/>
<input type="submit" value="Save Page"/>
</form>
Also what #DanielRoseman said. But hey, it might come further down the road.