How do you submit a form from Django server side? - django

I have a form with some paypal fields and other fields specific to my application. I would like to submit the form to my server, have it process some of the fields and then forward it onto the paypal handler url for payment. If I use the following in my server code:
if request.method == 'POST':
// Process some form elements
// Forward on to paypal
return HttpResponseRedirect("https://www.paypal.com/cgi-bin/webscr")
The problem is that the original form does not get posted with the redirect. How can I make this into an HTTP post with the original form so that they are redirected to Paypal and able to login and complete payment?

you can use http.client to make POST requests. Below is a link to the documentation and examples.
http://docs.python.org/3.1/library/http.client.html

I think that also accepts GET requests, meaning that you can pass that form data in the url. So you should be able to do along these lines...
if request.method == 'POST':
// Process some form elements
// Forward on to paypal
return HttpResponseRedirect("https://www.paypal.com/cgi-bin/webscr?%s" % "&".join(["%s=%s" % (key,value) for key,value in request.POST.iteritems()]))

Related

Issue with django rest framework while handling url-encoded data

I am building a REST API server that handles POST requests. The content type in the request is "application/x-www-form-urlencoded".In the request body, we are sending "data1" (some string) and "image" ( a file)
Here's the sample inputForm code I have:
from django import forms
class RequestForm(forms.Form):
data1= forms.CharField(label='data1',max_length=10000)
image = forms.ImageField()
I then validate the content in the form request:
if request.method == 'POST':
form = RequestForm(request.POST)
print("Form content: {0}".format(form))
if form.is_valid():
print("Works")
else:
print("Issue")
Now, when I send the above mentioned data, I always get an error. It prints "Issue". In addition, the line taht prints form content shows it as an error. Something like:
<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="data1" maxlength="10000"
One interesting point: if I remove "Content-type" from the request header, it works.
Any inputs on how I can read the form data correctly when we use content type as application/x-www-form-urlencoded.
thanks in advance...
As per Django Forms documentation:
By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception
You are on the right track, you should send the form as multipart/form-data as per this thread: Thread about form Content types
Found the solution. To begin with, I am sending a file in the input. So I should use content type as "multipart-formdata".
In addition, I am using Postman to pump in the REST API requests. In the body of the request, I set form-data which automatically sets the headers correctly based on what I am sending in the body. I was trying to override it with my own header which is not right.
When I resent my http POST request with no headers in Postman, it worked. (of course, I did verify the final http request itself and confirmed Postman is setting the header correctly)

Sending form to another view django

I am building a website and I want various views that will ask the user to request a quote from our page. I want to keep the code as DRY as possible so I am writing a view quote which will receive the quote requests from various views and, if there is a validation error redirect back to the page that made the request. I managed to solve this using the super bad practice 'global variables'. I need a better solution, I would like redirecting to respective view with the current form so I can iterate through the form.errors. Here is my code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
global session_form
session_form = form
return redirect('Main:' + quote_for) # Here I would like to send form instead of storing in global variable`
You can use the HttpResponseRedirect function, and pass as argument the page that made the request.
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
All the META data is store on a dictionary, if you want to learn more check the documentation.
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
If you redirect to the referrer, form.errors will be empty, as redirection is always a GET request.
I can think of two solutions to your problem:
Submit forms asynchronously using JavaScript and so populate the errors
Make all the views containing the form support POST - one way to do this would be to create a base class that inherits from FormView
The second option is a typical way of handling forms in Django - you process both POST and GET inside the same view.
After two days of searching I finally found the answer. Instead of saving form in request.session I just save request.POST and then redirect. Here is the code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
request.session['invalid_form'] = request.POST
return redirect('Main:endview')
def endview(request):
session_form = request.session.pop('invalid_form', False)
if session_form:
form = Quote(session_form)
# render template again with invalid form ;)
Now I can repeat this with all the views I want and just change the what_for input of each form to match the respective view (Like I intended).

How to add fields to a request?

I have a login page. Upon submission if 'webmail' is selected, the request
should be redirected to the webmail server, with the credentials submitted but
under different keys. Here's what I'm trying now:
if form.validate_on_submit():
if form.destination.data == 'webmail':
form.rc_user.data = form.email.data
form.rc_password.data = form.password.data
return redirect('https://example.com/webmail/', code=307)
This almost works: the POST is redirected to webmail. However the values
submitted are the default values, not the assigned values.
I have some more issues though:
the keys should be _user and _pass, but Flask seems to blow up with
leading-underscore field names.
I do not want to add these fields to the original class. I want to subclass
upon submission, somewhat as follows:
if form.validate_on_submit():
if form.destination.data == 'webmail':
class WebmailLoginForm(LoginForm):
rc_user = EmailField('user', default=form.email.data)
form = WebmailLoginForm(request.form)
return redirect('https://example.com/webmail/', code=307)
When I do this, the added fields show up as UnboundField and are not
submitted.
When issuing a redirect, the browser is simply told to resubmit to another server. I.e. it's too late for the server to influence the request.
So either: start a new request, or use javascript to change the submit target.
Thanks to my colleague Johan for kickstarting my brain.

payment processing with django

I am trying to build code that allows people to pay for the services that they get from my website. I have built the form using the forms.Form model available in django. I have also used the following pattern to build my view.
if request.method == 'POST'
form = ContactForm(request.POST)
if form.is_valid(): # All validation rules pass
conn = urllib2.Request(payment_gateway_url,urllib.urlencode(my_dat_in_dict))
f= urrlib2.urlopen(conn)
all_results=f.read()
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
The problem i am facing is that my forms get submitted OK and the payment gateway responds back to me with a whole bunch of html that helps the user to choose the credit card details etc in the response to this form POST(details that i am not collecting on my website). I can see this in the all_results (f.read()).
My question is that how do i show the user this page, since i get this as a result of my form POST. Should i save this response in a html file and HTTPResponseredirect to that page. I am assuming that HTTPResponseRedirect is more for a complete transaction and not the intermediate responses.
So, basically how do i handle the situation where the user will get sent to the payment gateway site and then after completing the proceedings come back to my site?
thanks
First off, I would say, if you live in the US, check out Stripe (or something similar). The way you are describing your payment process seems a bit overly complicated.
With that said, if (and I doubt this is the case), the HTML returned from the most is in the correct format for display on your website, you can just stick it in to an HttpResponse (must be a sprint)
return HttpResponse(html)
Otherwise, use something like BeautifulSoup, Scrape.py, or something similar to format it IN RAM, and then use HttpResponse. I would not write it to the file system for modification.

How to write good form validation in Django?

I've seen Django's samples and I can see they have decent error handling. However I want to see if there is yet a better approach, a general pattern to handle form validation errors in Django. This is the sample I found here:
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(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 = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
In particular, I was wondering:
How can the view in "/thanks/" be sure that the form was validated? Are there any common ways to pass the successful validation of the form to the next view? Or do I need to do something manually such as setting a flag in request's session?
How can one write this code in a way that when form is NOT valid and the page is shown with errors upon submission, if user refreshes the browser it wouldn't ask the user if they want to POST data again?
EDIT: With regards to #1 I am referring to cases like user manually entering the '/thanks/' url or going back and forth through history pages and accidentally openning it without any form being validated. (Do we still show the "thanks" page? or we need to somehow re-validate why we are in thanks view).
The view can be sure that the form is validated because it will only be called if the form is valid...
If the page is generated through a post request the browser will always ask you that when hitting refresh... I guess the only way to avoid this would be redirecting to another page!
How can the view in "/thanks/" be sure that the form was validated?
form.is_valid() should thoroughly check any field or - if necessary - any combination, cornercase, etc. That's basically it. The views knows, the form was valid if it renders. There is no need to include redundant information in the session.
How can one write this code in a way that when form is NOT valid and the page is shown with errors upon submission, if user refreshes the browser it wouldn't ask the user if they want to POST data again?
I am not sure what the point would be. The form contains errors and the user may correct them or leave. To render a page that would not ask for form resubmission, one could use a redirect, just as in the valid case. The error markup would have to be done manually in that case.