Integrate PayPal in Django app using Paypal Python SDK - python

I'm working on a project in which I'm using Python(3.6) & Django(1.10) and I need to implement Paypal payment method in this project. I have decided to use the official Python SDK from Paypal instead of other third-party packages.It's not only the csrf problem but it also how we can render a custom form for paypal checkout button.
Here's wwhat Ihave tried.
According to the docs as Here.
Here's my template:
<form class="form">
{% csrf_token %}
<div id="paypal-button"></div>
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
var CREATE_PAYMENT_URL = '{% url 'users:payment' %}';
var EXECUTE_PAYMENT_URL = 'https://my-store.com/paypal/execute-payment';
paypal.Button.render({
env: 'sandbox', // Or 'production'
commit: true, // Show a 'Pay Now' button
payment: function () {
return paypal.request.post(CREATE_PAYMENT_URL).then(function (data) {
return data.paymentID;
});
},
onAuthorize: function (data) {
return paypal.request.post(EXECUTE_PAYMENT_URL, {
paymentID: data.paymentID,
payerID: data.payerID}).then(function () {
// The payment is complete!
// You can now show a confirmation message to the customer
});
}
}, '#paypal-button');
</script>
</form>
From urls.py:
url('^payment/$', views.PaymentProcess.as_view(), name='payment'),
From views.py:
class PaymentProcess(LoginRequiredMixin, generic.DetailView):
def post(self, request, *args, **kwargs):
mydict = {
'paymentID': 'PAYMENTID',
}
print('Getting payment request')
return json.dumps(mydict)
When Paypal submits a post request to /payment it returns 403 Forbidden error due to csrf_token. How can I pass the csrf_token with this request.
Any resource or tutorial will be really appreciated.

It seems you can add custom headers to your post request : https://github.com/paypal/PayPal-Python-SDK/blob/master/paypalrestsdk/api.py#L270
Given that you just have to add you csrf token to the headers : https://docs.djangoproject.com/en/2.0/ref/csrf/#setting-the-token-on-the-ajax-request
And your server should give you access

Related

How do I dynamically change the value of text in html whenever a python variable is changed using ajax?

I'm using ajax, python, Django, HTML, and javascript for my project.
I'd like to know, if there is a p in my HTML file like,
<p class='text_box', id='tbox'>
{{ text_variable_from_python }}
</p>
<input class='input_box', id='ibox', type='text'>
And if I'd input some text into the input box, make a simple ajax request with the "text" variable and get an output from the server, which I would update on the views.py as,
def main(request):
if request.method == 'POST':
new_text = request.POST['text']
context = {'text_variable_from_python': new_text}
else:
context = {'text_variable_from_python': 'You can change me!'}
print(context)
return render(request, 'Main.html', context=context)
My question is, how do I send the data dynamically from the server to appear on client's webpage using ajax and python in between the two?
Using my method, I can only see "You can change me!" on the webpage or nothing at all. No matter how many differing prompts I give, further changes do not show on the webpage.
EDIT:
My ajax code for sending the variable.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
function update_dialogue() {
$.ajax({
type: "json",
url: "update_text",
success: function(data) {
document.getElementById("tbox").value = data['text_variable_from_python'];
}
});
}
My ajax code for recieving the variable.
<script>
function getInputValue() {
let inputVal = document.getElementById("ibox").value;
document.getElementById("ibox").value = '';
$.ajax({
type:'POST',
url: 'main',
data: {csrfmiddlewaretoken: "{{ csrf_token }}",
'text': inputVal,}
});
}
</script>

How to call Python functions from JavaScript in Django?

I've been struggling on this for a couple days. I've read through many posts, blogs, and watch video demo on Django projects, but nothing quite answers my problem.
I have a Django webapp that uses a Python API to connects to a third-party service to analyze text data. The user writes into a text area, presses the button, then the text is sent to the service which returns a list of JSON objects. The API call to this service is a Python function. I'm trying to use Ajax to make an async call to the Python function using the text data as a param when the button is pressed.
I'm not at this time trying to invoke my third-party service, yet. I'm just trying to see if I can get a response from Python sending input and receiving output.
Most of the examples I've found involve creating a form and submitting it so the Django framework automatically calls it's Python functions. A form is not exactly what I'm trying to build, nor am I wanting to proceed to a new page to see the results or refresh the current one.
<!-- index.html -->
<html>
<head>
<title>Test Data</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
document.getElementById("Button").addEventListener('click', analyzeText());
function analyzeText(){
var text = document.getElementById('text-to-analyze').value;
$ajax({
type: "POST",
url: "/models.py", /* Call python function in this script */
data: {param: text}, /* Passing the text data */
success: callback
});
}
function callback(response){
console.log(response);
}
</script>
</head>
<body>
<textarea id="text-to-analyze" rows="12" cols="100"></textarea><br>
<button id="button" value="Analyze"/>
</body>
</html>
# models.py
from django.db import models
# Function I want to call from Ajax
def testcall():
return 'test successfull'
EDIT:
I almost have it working. I'm just getting syntax errors with ajax I can't figure out.
Could not parse the remainder: ' 'ajax-test-view'' from 'url 'ajax-test-view''
EDIT
I fixed all the syntax errors but now I'm getting 404 errors when trying to execute the target python script. I now understand how url and pathing works in Django, but using Kostadin Slavov's solution, how can I do this without routing to a specific html?
In the ajax, I'm setting the url like this:
url: '{{ 'ajax-test-view' }}',
And in my python I have the url pattern set like this:
path(r'^django-app/$', views.testcall, name = 'ajax-test-view'),
It seems like the variable in the ajax url points to the name field in the url pattern, but that also seems to be the name of a specific html file to render(?) Or is it the name of the py function?
When I click my button the ajax sends a command to http://localhost:8000/what-ever-the-name-field-is-in-the-url-pattern and I get a 404 from it. Is the framework trying to load a page or does it mean it can't find my python file?
Derp... It's important to know that url: '{{ 'ajax-test-view' }}', is the url address ajax will request and Django's url dispatcher intercepts it to do something else only if the path matches perfectly.
FINAL EDIT
Got it working. A couple things I changed in Kostadin Slavov's solution:
# urls.py
urlpatterns = [
url(r'^$', views.index, name = 'index'),
path('my-ajax-test/', views.testcall),
]
<!-- index.html -->
<script>
....
var text = "test successful";
$.ajax({
type: "POST",
url: '{{ 'my-ajax-test/' }}',
data: { csrfmiddlewaretoken: '{{ csrf_token }}', text: text },
success: function callback(response){
console.log(response);
}
});
</script>
# views.py
def testcall(request):
return HttpResponse(request.POST['text'])
in the urls.py you create an url
path('my-ajax-test/', views.myajaxtestview, name='ajax-test-view'),
then your ajax should loook like
pay attention to the csrf_token otherwise will send you an error
$ajax({
type: "POST",
url: '{{ url 'ajax-test-view'}}',
data: {csrfmiddlewaretoken: '{{ csrf_token }}',
text: "this is my test view"}, /* Passing the text data */
success: function(response){
alert(response);
}
});
in views.py
def myajaxtestview(request):
return HttpResponse(request.POST['text'])
Summary:
you need to create the url in your urls.py which leads to your views.py
then the view gets the data that you've sent in the request.POST in the request you have plenty of data you can find more about it here.
in your case you are more interested in request.POST it's a python dictionary
so you pick the parametre that you have send and work with it
you may play with it like return HttpResponce('test'+ request.POST['text'])
If you want to get something from models.py let's say you data that you sent from the js is {object_type: hammer}
def myajaxtestview(request):
look_for = request.POST['object_type']
#lets say you have model Items
my_items= serializers.serialize('json', Items.objects.filter(object_type=look_for))
return JsonResponse(my_items)
Use AJAX
Add this in your html file
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Then use this in your js file
$.ajax({
type: "POST",
url: "Your defined route in urls.py file", #then in your views.py you can define your operations
data: {
csrfmiddlewaretoken: '{{ csrf_token }}',
text: your_input
}, /* Passing the text data */
success: function(response) {
alert(response); #response form your request
}
});
You have to receive this post request in your views.py file as:
request.POST.get("key")
What you are trying is a well known problem. When you do ajax request to the server , the server responds with some data or may be renders a template.
For this request - response cycle to work, you will have to create a mapping of the url to the controller logic. You will have to create a url and a python function mapping in urls.py.
The python function will be in views.py. Now when you request for that url with the given method(POST or GET), it will call the mapping function and return the result.
After reading the question edits and the different answers, this is
what worked for me (doesn't include imports):
File: urls.py
#urls.py
urlpatterns = [
path('', views.index, name = 'index'),
path('my-ajax-test/', views.testcall),
]
File: index.html
#index.html
<html>
<head>
<title>Test Data</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
function analyzeText(){
var text = document.getElementById('text-to-analyze').value;
$.ajax({
type: "POST",
url: '{{ 'my-ajax-test/' }}',
data: { csrfmiddlewaretoken: '{{ csrf_token }}', text: text },
success: function callback(response){
/* do whatever with the response */
alert(response);
}
});
}
</script>
</head>
<body>
<textarea id="text-to-analyze" rows="12" cols="100"></textarea><br>
<input type="submit" id="button" value="process" onclick="analyzeText();">
</body>
</html>
File: views.py
#views.py
def index(request):
return render(request, 'vote/index.html')
def testcall(request):
#Get the variable text
text = request.POST['text']
#Do whatever with the input variable text
response = text + ":)"
#Send the response
return HttpResponse(response)
I struggled with this issue for a day or two. Here's what solved my problem.
EDIT: I also needed to download the full version of jquery to get the ajax request working.
HTML
In your HTML you need to add {% csrf_token %} to your form
<form id="your_form">
{% csrf_token %} //include the csrf_token line in your form
<div>
<input type="submit" value="blah blah blah">
</div>
</form>
script.js
For your java script code add this function to get the csrf cookie.
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
Next you need to add the csrf token into your ajax request as follows.
var csrftoken = getCookie('csrftoken');
$.ajax({
type: "POST",
url: '/my-url/', --your url here
data: { csrfmiddlewaretoken: csrftoken, text: "your text data here" },
success: function callback(response){
console.log(response);
}
});

Requests in Django

I'm newer in Django and some time ago I've totally stuck on problems with my requests. I'm trying to do POST from Django form. I do that with json and AJAX
Here is my code
form.py
class PostForm(forms.ModelForm):
class Meta:
model = Message
fields = ['message_text']
widgets = {
'message_text': forms.TextInput(
attrs={'id': 'message_text', 'required': True,
'placeholder': 'new message...', }),}
views.py
def index(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.cleaned_data
message_t = request.POST.get('message_text')
response_data = {}
new_mess = Message(message_text = message_t,
post_time = message_t.created,
username="second")
new_mess.save()
response_data['result'] = message_t
else:
response_data['result'] = 'nothing...'
else:
form = PostForm()
template = loader.get_template('chat/index.html')
context = RequestContext(request, {
'form': form, })
return HttpResponse(template.render(context))
(In another variant of views.py I tried to separate POST request handling to another function, but it doesn't work as well)
html:
<form method="POST" id="post-form">
<td class="col-lg-6"><div class="fieldWrapper" id="the_post"
class="form-control" type="text">
{{ form.message_text }}
</div></td>
<td class="col-lg-6"> <input type="submit" value="Post"
class="btn btn-success" name = "Post"></td>
</form>
js:
$(function() {
$('#post-form').on('submit', function(event){
event.preventDefault();
console.log("form submitted!") // sanity check
create_post();
});
function create_post() {
console.log("create post is working!") // sanity check
$.ajax({
url : "/chat/new_message/", // the endpoint
type : "POST", // http method
data : { the_post : $('#post-form').val() },
success : function(json) {
$('#post-form').val(''); // remove the value from the input
console.log(json); // log the returned json to the console
console.log("success");
},
error : function(xhr,errmsg,err) {
...
}
});
};
});
In the result my POST is successful, no error appears, but no record in the base created too.
Note: Also I've excluded csrf everywere
Can someone help me to figure out what's wrong?
The form is not valid. It can never be valid, because you are sending a JSON dictionary with the form data inside the key "the_post", but you haven't told the view to look there.
And the view can't report back the status of the form, because you construct a response - "response_data" - and then ignore it.
Finally, your view does not send back JSON anyway - it sends back the rendered template, as if it were a normal non-Ajax view - so the receiving JS has no idea what to do with it.
I've found the fix for my POST.
The main problem was in json body, I was using wrong value name, it has to be:
data : { the_post : $('#message_text').val() },
Now request is not empty.

How to return django form object in an AJAX request from django template?

I am trying to call my view from django template via an Ajax call.
I want the form object in response from view such that I can render this form via jquery in a div element.
Is it possible ? How?
This is what i tried:
home.html
function get_edit_form(button, id)
{
$.ajax({
url: "/manage/licenses/{{mls_signup_code}}/{{agent_id}}/" + id + "/",
type: "get",
data: {id: id},
success: function(response) {
console.log(response);
$("#formdiv").html({{ response.as_p }});
}
})
}
Views.py
elif request.method == "GET":
owned_license_id = request.GET.get('id', '')
form = OwnedLicenseForm(owned_license_id)
return form
I see what you are trying to do, but you cannot render the html form this way:
$("#formdiv").html({{ response.as_p }});
I think you are confusing server side rendering (Django templates) with client side rendering. Server side rendering happens when your server is processing the request, it cannot render objects produced by javascript running in the browser.
Because response is a javascript object, obtained by jquery sending an Ajax request to your url. At this time, the page has already been rendered by Django's template engine, and sent to the browser. There is no way for Django template to even be aware of this response.
I understand you want to use the as_p() method to render the form, you can do it like this:
function get_edit_form(button, id)
{
$.ajax({
url: "/manage/licenses/{{mls_signup_code}}/{{agent_id}}/" + id + "/",
type: "get",
data: {id: id},
success: function(response) {
console.log(response);
// response is form in html format
$("#formdiv").html(response);
}
})
}
# Views.py
elif request.method == "GET":
owned_license_id = request.GET.get('id', '')
form = OwnedLicenseForm(owned_license_id)
return HttpResponse(form.as_p()) # return a html str
You can accomplish this with a combination of Django and JQuery.
Step 1: Create an ultra simple form_from_ajax.html Template
The template can be as simple as {{form.as_p}}. The point is to not inherit your base template. You're simply using this form_from_ajax.html template to render the HTML of the form.
Step 2: Create a View with a slug argument that helps you get the correct form
def payment_method_ajax(request, method): # method is your slug
"""Load a dynamic form based on the desired payment method"""
options = {
'ach': ECheckForm(), # Dynamic form #1
'credit-card': CreditCardForm(), # Dynamic form #2
}
if method in options.keys():
context = {'form': options[method]}
else:
context = None
template = 'your_app_name/form_from_ajax.html'
return render(request, template, context)
Step 3: Define the AJAX url in urls.py
[...
path(
'payment-method-ajax/<slug:method>/', # notice the slug in the URL
views.payment_method_ajax,
name='payment-method-ajax'),
...]
Step 4: Update your template where you'd like the AJAX loaded form to appear
Make some buttons to have the user select an approprate form option
<button id="btn_ach" onclick="load_payment_form(this)">ACH</button>
<button id="btn_credit_card" onclick="load_payment_form(this)">Credit Card</button>
form-fields is where the dynamic form will be loaded
<form id="id-form" style="display: none;">
{% csrf_token %}
<div id="form-fields"></div>
<input type="submit" value="Save Payment Details"/>
</form>
Make sure to add slugs to your main view's context
context = {
'target': 'Add a New Payment Method',
'h1': 'Add a New Payment Method',
'ach': 'Save an ACH Profile',
'credit_card': 'Save a Credit Card Profile',
'slugs': ['ach', 'credit-card'], # Here are the slugs ****
}
Step 5: Load the form with JQuery and the button's onclick
<script>
var ach = 'ACH';
var creditCard = 'Credit Card';
var form_urls ={
ach : '{% url "payment-method-ajax" slugs.0 %}',
creditCard : '{% url "payment-method-ajax" slugs.1 %}',
}
function load_payment_form(btn) {
if(btn.innerText==ach) {
get_url = form_urls['ach'];
type = ach;
}
else if(btn.innerText==creditCard) {
console.log('Load credit card form');
get_url = form_urls['creditCard'];
type = creditCard;
}
$.get({'url': get_url}).done(
function(data) {
document.getElementById('form-fields').innerHTML = data;})
document.getElementById("id-form").style.display = "block";
}
</script>

Using the Django URL Tag in an AJAX Call

There are LOTS of post and pages discussing the use of Django and AJAX, and I've read hundreds over the past day or so looking for the answer to this question. A quick overview:
May of the examples show a hard-coded URL like this:
$.post("/projects/create/", {"name" : name}, function(data) {...
or some use the URL template tag, but with no parameters:
$.post("{% url create_project %}", {"name" : name}, function(data) {...
However, I'd like to include a Django-style parameter in a URL. Here's my url definition:
url(r'ajax/entity_name/(?P<pk>\w+)/$',EntityAjaxView.as_view(),name='entity_name'),
Yes, I'm using a class based view, and it is based on DetailView. This view looks by default for a pk value to be provided in the URL, and in a normal template I would use:
{% url entity_name id_number %}
to provide a link. In my code, I want to grab the value entered in an input box for the pk value. Here is a snippet of my JavaScript (which doesn't work):
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val()
$.ajax({
type: "GET",
url: '{% url entity_name id_number %}',
So, my question is, can I use the URL template tag with a value from an input box?
(I know that I could use POST instead of GET and pass the id_number in the POST data, but that won't work well with the DetailView.)
Django is a server-side application. Javascript is client-side. Django templates get rendered on the server, so {% url entity_name id_number %} is evaluated on the server side, and then it's value is returned to the client. Just because of this, it's impossible for you to combine Django templates with javascript. However there are couple of things you can do to solve your problem.
Since you are making an ajax call, and the ajax call depends on some user input, usually the best route for the client to send any type of user input to the server is by either using querystring (thing after ? in the URL) or by sending a POST data. So the simplest thing is to change your your url not to include the pk in the url, but for the view to get that as part of GET or POST data.
url(r'ajax/entity_name/$', EntityAjaxView.as_view(), name='entity_name'),
and the view (sorry I'm not familiar with class based views):
def entity_name(request):
pk = request.GET.get('pk')
...
That seems to me to be the most elegant solution. If however you absolutely need to construct the url on the client side, you can generate a template url on the server side and then replace whatever parts you need on the client side to get the full url. This however requires more maintenance and therefore is more error prone. Simple js example of this approach:
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val(),
url = '{% url entity_name 0 %}'.replace('0', id_number);
$.ajax({
type: "GET",
url: url,
...
});
It is possible to set an Ajax url on the element you are selecting using an attribute and it will behave like Django urls. Importantly, you can even access the url in Javascript file. I use it a lot
HTML
<div class="card-body" id="js-products" data-url="{% url 'chart-data' %}">
<div class="chart-area">
<canvas id="testChart"></canvas>
</div>
</div>
Note: the data-url attribute set on parent div
JAVASCRIPT
$(document).ready(function () {
var endpoint = $("#js-products").attr("data-url");
var defaultData = [];
var labels = []
$.ajax({
method: 'GET',
url: endpoint,
success: function (data) {
labels = data.labels
defaultData = data.data_default
setChart()
},
error: function (error_data) {
console.log(error_data)
}
})
function setChart() {
var ctx = document.getElementById('testChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
responsive: true,
data: {
labels: labels,
datasets: [{
label: 'Monthly Performance',
data: defaultData,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
});
DJANGO VIEWS
Am using django rest framework class view but you can use either of function or class based view
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
labels = ['Products', 'User', 'May']
data_default = [SeedProduct.objects.all().count(),
User.objects.all().count(), 4]
data = {
'labels': labels,
'data_default': data_default,
}
return Response(data)
DJANGO URLS:
import the view class from views
path('api/chart/data', views.ChartData.as_view(), name="chart-data"),
It's pretty time consuming to go round trip to a server just to fetch a URL. The best strategy to keep URLs dry and avoid this is to generate javascript that emulates Django's native url reverse function and then serve that code statically with the rest of your client side JS.
django-render-static does just that.
This worked for me.
my URL was:
path('myurl/<str:type>', views.myfunction, name='myfunction')
my views.py file:
def myfunction(request,type):
return render(request, "payment.html", context)
In my template, I solved the issue by:
<button type="button" class="btn"
onclick="myfunction('forward');">My Button Name
</button>
<script>
function myfunction(type){
let url = "{% url 'appName:myfunction' 'ok' %}".replace('ok', type);
$.ajax({
method: 'POST',
url: url,
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
}
});
}
</script>

Categories