Pyramid: using form data for route matching and POST simultaneously - python

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?

Related

Django Form request not saving data to db

I am using a django form in atemplate to save data entered to database.
In my view after the request is made, the response is redirected correctly but the data is not saved to db.
I might be missing something. but am unable to find it even after a lot of debugging.
here is what has been done so far:
views.py:
from .models import testmodel
def testview(request):
if request.method== 'POST':
form=MapForm(request.POST)
if form.is_valid():
test1=request.POST.get('t1')
print meaningid1
test2=request.POST.get('t2')
print meaningid2
pobj=testmodel(test1=test1,test2=test2)
pobj.save()
return HttpResponse('Successful')
after this the response message "Successful" is seen
from template:
<form action="/testview/" method="post"> {% csrf_token %}
{{form.as_p}}
<input type="text" name="t1" value='' id='t1'/> <br><br><br>
<input type="text" name="t2" value='' id='t2'/><br>
<input type="submit" value="Submit" />
</form>
from forms.py:
from .models import testmodel
class MapForm(forms.ModelForm):
class Meta:
model = testmodel
fields = ['test1','test2']
after the data is entered in form it is going to page /testview and showing message on page. but from backend data is not been saved to db.
Can some one suggest what could be done
Thanks
In python, indentation matters.
def testview(request):
if request.method== 'POST':
form=MapForm(request.POST)
if form.is_valid():
test1=request.POST.get('t1')
print meaningid1
test2=request.POST.get('t2')
print meaningid2
pobj=testmodel(test1=test1,test2=test2)
pobj.save()
return HttpResponse('Successful')
In the above code 'Successful' will be displayed regardless of whether the form is actually successful or not. You need to push your return statement four spaces to the right, and you also need to add an else clause which handles the situation where the form is not valid. Typically that is just to display the form again (with form errors which wil be displayed for you automatically is you use form.as_p or form.as_table)

how to manipulate user submitted text and display it with django?

I want to build a very simple webapp that takes a user's text, runs a function on it that alters it and then displays the altered text. I have the code for the function but everything else is unclear.
I am very new to django and just need a push in the right direction with this problem. At the very least, tell me what to google, I've went through several tutorials but neither of them dealt with this kind of task.
Thanks in advance!
Define a form; in forms.py under your app's folder
class MyForm(forms.Form):
myinput = forms.forms.CharField(max_length=100)
Define a function in your views.py
import .forms
def handle_form(request):
if request.method == 'POST': # If the form has been submitted...
form = MyForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = MyForm() # An unbound form
return render(request, 'handle_form.html', {
'form': form,
})
Add a template
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Of course you need to add it to your urls.py
Most info was copy pasted from: https://docs.djangoproject.com/en/1.8/topics/forms/

How to post to a view in django from a django template?

Heres the scenario:
I have a email subscriber/un-subscriber app. I am stuck up in the un-subscribing a user part. The user is given a link, which if he/she follows will be able to un-subscribe. The link is typically a view, in the following format:
r^'/unsub_view/(?P<user_id>\w+)/$'
So, when the user follows this links he/she is doing a GET request on the view unsub_view with a parameter user_id. So I have coded up my view as:
def unsub_view(request, user_id):
if request.method == 'GET':
### Do some DB lookup to determine if it is a valid user or not
if user_is_valid:
return direct_to_template(request, '/app/unsub.html', {'user': user})
Now when a valid user is doing the GET, a confirmation dialogue is shown, along with a button. If he/she clicks on the button, I want the template to post the 'user' to the same view, thus the unsub_view also has this piece of code:
if request.method == 'POST':
if user_is_subscribed:
#Unsubscribe the user.
else:
#Show error meessage.
My question is how can I have the button in my template to post to this view ? I have looked around but I got POST-ing to a .php or .asp
Please help.
Note: If there is a better workflow idea, I am also open to that, so please do suggest if there is one.
In the template unsub.html rendering the form with the button, you should pass the url of your view using the reverse method
from django.code.urlresolvers import reverse
def unsub_view(request, viewid):
if request.method == 'POST':
if user_is_subscribed:
#Unsubscribe the user.
submit_url = reverse('unsub_view', viewid)
return direct_to_template(request, '/app/unsub.html', {'user': user, 'submit_url'})
else:
#Show error meessage.
in your template you can then render the form like follows :
...
<form method='post' action='{{ submit_url }}'>
{% csrf_token %}
<input type="hidden" value="{{ user_id }}" name="user_id" />
<input type="submit" value="unsubscribe"/>
</form>
...
Django also has a full framework dedicated to form modeling and rendering. You could take advantage of that to generate the form.

Additional field in django form

I am creating a form in Django. When I POST the data, the data is naturally sent. My problem is, I want to pass an additional property to the POST data, that is not any of the form fields, but an additional one.
So that I can later do something like (pseudocode):
def form_view(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
extra_field = form.cleaned_data['extra_field']
#or maybe
extra_field = form.extra_field
#...
else:
form = MyForm()
#...
Anything that might work in order to pass an extra property, which is not a field but a simple variable, to the POST request.
If you want to pass anything to django as a POST request from the HTML, you would use a hidden input
<input type="hidden" name="foo" value="bar" />
print request.POST['foo'] # out: bar
If you want to modify the POST dictionary in python from your view, copy() it to make it mutable.
mutable_post = request.POST.copy()
mutable_post['foo'] = 'bar'
form = MyForm(mutable_post)
There are a few ways to do this. One, is you can just add it to your template.
<form action="." method="post">{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="extra_field" value="{{ extra }}" />
<input type="submit" value="submit" />
</form>
Another way is to add the field to your form class, but use a hidden widget. I'm not sure if this is what you want. If it is, just add a comment and I can explain this point further.
In your form's clean method, you can add new information to the cleaned_data, something like: form.cleaned_data['extra'] = 'monkey butter!', then if the form.is_valid(), you have your extra info.
What you do finally will depend on what your extra information is, and where it is available to you.

Django 1.1.1 chokes on multipart/form-data

Initial story
I'm trying to implement file upload using a simple form (I'm pasting stripped version, but all important parts are included):
<form method="POST" action="" enctype="multipart/form-data">
<input type="file" name="up_file" size="50">
<input type="hidden" name="cpk" value="{{c.pk}}">
<input type="submit" name="btn_submit">
</form>
Now, server-side script running under wsgi was receiving strange values for "cpk" field and request.FILES was empty empty request.FILES and request.POST dictionaries, so I decided to switch to development server for debugging.
Surprisingly, ipdb debugger hangs after typing both request.POST and request.FILES and pressing enter... On the other hand, when I remove enctype="multipart/form-data" from tag, I'm able to check both request.POST and request.FILES, but of course request.FILES is empty then.
(Also wsgi version seems to be healed by removal of enctype="multipart/form-data"...)
Update
I tried all combinations of Opera 10//Firefox 3.5, enctype="multipart/form-data"//no multipart/form-data and dev server//mod_wsgi. The result is that it's enctype="multipart/form-data" that breaks the show. So now I'm going to check Django bugtracker if it's a known issue.
Meantime, maybe someone here can point me in the right direction
You may need to provide your view and form code as we use form uploads with enctype="multipart/form-data" in Django 1.1.1 with great success.
The following dummy app, for example, works perfectly in the dev server.
views.py
from django import forms
from django.shortcuts import render_to_response
class UploadForm(forms.Form):
cpk = forms.CharField(max_length=256)
f = forms.FileField()
def my_upload_view(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
print "Got cpk",form.cleaned_data['cpk']
print "Got file",request.FILES['f'].read()
else:
form = UploadForm()
return render_to_response('upload.html', {'form':form})
upload.html
<html>
<body>
<form enctype="multipart/form-data" method="post">
{{ form.f }}
{{ form.cpk }}
<input type="submit" />
</form>
</body>
</html>
I'm using the django form instance to render the file input, but it renders the very common <input type="file" name="f" id="id_f" />.
Using this sample, I get the content of the file (I've tested using a simple text file) printed to the terminal from my dev server. The few gotchas and tests I can recommend are:
ensure that the file you are uploading is less than settings.FILE_UPLOAD_MAX_MEMORY_SIZE (the default is 2.5 MB)
double-check that you haven't defined any custom file upload handlers that may be breaking the upload process (settings.FILE_UPLOAD_HANDLERS)
try uploading a very simple file (like a small text file) to see if the issue still persists with something basic
use a tool to inspect the raw HTTP request/response traffic (firebug will do this for you, and there are some stand-alone apps that will act as a proxy to help you here too)... sometimes the solution will jump out when you can see the raw traffic.
In case you haven't found them yet, the django file upload docs have a fair number of examples.

Categories

Resources