I'm currently working on a pyramid project, however I can't seem to submit POST data to the app from a form.
I've created a basic form such as:
<form method="post" role="form" action="/account/register">
<div class="form-group">
<label for="email">Email address:</label>
<input type="email" class="form-control" id="email" placeholder="you#domain.com">
<p class="help-block">Your email address will be used as your username</p>
</div>
<!-- Other items removed -->
</form>
and I have the following route config defined:
# projects __init__.py file
config.add_route('account', '/account/{action}', request_method='GET')
config.add_route('account_post', '/account/{action}', request_method='POST')
# inside my views file
#view_config(route_name='account', match_param="action=register", request_method='GET', renderer='templates/account/register.jinja2')
def register(self):
return {'project': 'Register'}
#view_config(route_name='account_post', match_param="action=register", request_method='POST', renderer='templates/account/register.jinja2')
def register_POST(self):
return {'project': 'Register_POST'}
Now, using the debugger in PyCharm as well as the debug button in pyramid, I've confirmed that the initial GET request to view the form is being processed by the register method, and when I hit the submit button the POST request is processed by the *register_POST* method.
However, my problem is that debugging from within the *register_POST* method, the self.request.POST dict is empty. Also, when I check the debug button on the page, the POST request is registered in the list, but the POST data is empty.
Am I missing something, or is there some other way of access POST data?
Cheers,
Justin
I've managed to get it working. Silly me, coming from an ASP.NET background forgot the basics of POST form submissions, and that's each form field needs a name== attribute. As soon as I put them in, everything started working.
That does nothing, I belive.
return {'project': 'Register_POST'}
POST parameters are stored inside request, so you have to do something like this.
def register_POST(self, request):
return {'project': request.POST}
To access email input (which has to be named, for example: name="email"), use get() method:
request.POST.get('email')
<form method="post" role="form" action="/account/register"> {% csrf_token %}
Try using "csrf token". hope it works. remaining code looks fine.
Related
I am currently using HTMX and Django to process button clicks within a table that adds the selected item to a list. I am trying to use the name/value HTML attributes to send to the backend with the value being dynamic based on the database information. I have the following form code:
<form action="" method="post">
{% csrf_token %}
<button hx-post="{% url 'add-analysis' %}" hx-target="#analysis-list" type="submit" name="projectChoice" value="{{project.project_title}}">Add</button>
</form>
in my Views.py I am trying to parse the data with the following code:
def add_analysis(request):
proj_name = request.POST.get("projectChoice")
print(list(request.POST.items()))
print(request.data())
return render(request, 'includes/analysis-list.html', {"selected_projects" : proj_name})
This returns None however. To debug this I tried listing all of the POST requests to the server with the following:
print(list(request.POST.items()))
However this only returns the CSRF token, what am I doing wrong here?
htmx sends the button value with the posted data when the request attribute hx-post is placed on the form itself.
<form hx-post="/form" hx-target="#result">
<button name="submit1" value="foo" type="submit">Submit 1 (foo)</button>
<button name="submit2" value="bar" type="submit">Submit 2 (bar)</button>
</form>
Here's a live example https://codepen.io/jreviews/pen/PoEJYMX
In your case you can try to do something different on the server side depending on the button that was used to submit the form.
Basically when a POST request is made, I want to redirect to another page.
def sample(request):
if request.method != "POST":
return render(request,"user/sample.html")
else:
return redirect("https://www.djangoproject.com")
This code works fine when it receives a GET request but when I submit
information, instead of redirecting to the page above, it appends the the template name into the url, Something like this :
http://localhost:8000/sample/sample
No matter what I type into the redirect(), even completely random things it still redirects to sample/sample
I've created multiple django-projects and in every one of them I still get this problem.
I've fixed the problem, leaving this here for anyone in the future.
My problem was in the html file
<form action="" method="POST">
{% csrf_token %}
{{form}}
<input type="submit">
the <form action=""> must be an empty string, otherwise it is going to append that to the url.
The problem had nothing to do with the redirect() function.
I am creating a form that allows users to edit an event saved to a django database. The problem is when it runs the code, a new instance is created in the database, the old one remains in the database and both are then available to view in the site
Below is (some of) the HTML form that is used to call the edit view and edit the instance in the database
<div class="modal-footer">
<form action="edit/" method="POST">
{% csrf_token %}
<input type="hidden" name="event_edit_id" id="event_edit_id">
<input class="btn btn-primary btn-block" type="submit" value="Save Changes"/>
</form>
</div>
Next, is the View that is used to edit the event for the id sent with the form:
def edit(request):
if request.method == "POST":
event_id = int(request.POST.get('event_edit_id'))
event = Events.objects.get(pk=event_id)
form = AddEventForm(request.POST or None, instance=event)
if form.is_valid():
form.save()
return redirect('calendar')
I know I am missing something but I just can't see it, any help appreciated!
EDIT
I've noticed that when the code is submitted for edit, it goes straight to /calendar/ instead of /calendar/edit so this is the urls file I use to map the files
urlpatterns = [
path('', views.calendar, name="calendar"),
path('delete/', views.delete, name="delete"),
path('edit/', views.edit, name="edit"),
]
Without seeing your form, I can only guess that there's nothing populating edit_event_id, so the form is saved as a new event. Currently, edit_event_id isn't a bound field, so it doesn't contain any data.
Ok so I got it, and it was impossible for anyone else to get it because the issue was further up in the code than in the I had included in the html.
My error was that I had not changed the code properly after a previous edit. There was another form that was open and I didn't delete the start of the form tag..
Basically, I didn't make sure the HTML tags each had an opening and closing tag.
On this is correct, the code above will work to edit entries :)
I'm using Pyramid to build a webapp, and I've got two views where one leads to the other:
config.add_route("new", "/workflow/new")
config.add_route("next", "/workflow/{id}/next")
The new view is really very simple and presents only an HTML form as a Jinja2 template for the user to fill in some information:
<form method="post" action="{{ request.route_url('next',id='') }}" >
<input type="text" name="id" value="Identifier" />
...
<input type="submit" name="next" value="Next" />
</form>
The question here regards the action of that form: how can I use the content of the text input field id, perhaps process it a little, and then pass it on in the route request?
Note that in this scenario the form data is passed from the new view to the next view, and that should stay the same.
When the form is posted, the forms fields will be available in the request object, see
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/webob.html#request
I believe it is also a good idea to post to the same url (<form action="#" method="post">), so that you can validate the form. Then you can process and redirect to the next url when the form is valid, or recreate the form with errors if it isn't.
So your view may end up something like this;
from pyramid.httpexceptions import HTTPFound
from pyramid.url import route_url
def myview(request):
if request.method == 'POST':
# Validate the form data
if <form validates successfully>:
# Do any processing and saving here.
return HTTPFound(location = route_url('next', id=request.params['id'], request=self.request))
else:
request.session.flash("The form isn't valid.")
# Do some stuff here to re-populate your form with the request.params
return { # globals for rendering your form }
There are already many questions/answers addressing this, such as How can I redirect after POST in Pyramid?
I am using a flask framework, and can't seem to delete rows from the database. The code below gives a 405 error: "The method is not allowed for the requested URL." Any ideas?
In the py:
#app.route('/delete/<postID>', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries WHERE id = ?', [postID])
flash('Entry was deleted')
return redirect(url_for('show_entries', post=post))
In the html:
<h3>delete</h3>
Clicking <a href...>delete</a> will issue a GET request, and your delete_entry method only responds to POST.
You need to either 1. replace the link with a form & submit button or 2. have the link submit a hidden form with JavaScript.
Here's how to do 1:
<form action="/delete/{{ entry.id }}" method="post">
<input type="submit" value="Delete />
</form>
Here's how to do 2 (with jQuery):
$(document).ready(function() {
$("a.delete").click(function() {
var form = $('<form action="/delete/' + this.dataset.id + '" method="post"></form>');
form.submit();
});
});
...
Delete
One thing you should not do is make your delete_entry method respond to GET. GETs are meant to be idempotent (are safe to run repeatedly and don't perform destructive actions). Here's a question with some more details.
Alternatively, change POST to DELETE to get you going.
#app.route('/delete/<postID>', methods=['DELETE'])
Ideally, you should use HTTP DELETE method.
I used flaskr as a base for my Flask project (as it looks like you did as well).
In the .py:
#app.route('/delete', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries where id = ?', [request.form['entry_id']])
g.db.commit()
flash('Entry deleted')
return redirect(url_for('show_entries'))
In the HTML:
<form action="{{ url_for('delete_entry') }}" method=post class=delete-entry>
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="submit" value="Delete" />
</form>
I wanted a button, but you could easily use a link with the solution here.
A simple <a href= link in HTML submits a GET request, but your route allows only PUT requests.
<a> does not support PUT requests.
You have to submit the request with a form and/or with JavaScript code.
(See Make a link use POST instead of GET.)