I am trying to create a django shopping site. But I can't get stripe to work. I don't belive it is anything workng in my code. It works fine withe the "tok_visa" sendt with javascript. But it does not accept my token. I have even tried manuelly writing it in.
views.py
if form.is_valid():
token = form.cleaned_data['token']
try:
stripe.Charge.create(
amount = 20000,
currency = "nok",
description = ""+form.cleaned_data['etternavn']+", "+form.cleaned_data['fornavn'],
source = token,
)
form.save()
return HttpResponse("<p>"+form.cleaned_data['fornavn']+"</p>")
except stripe.CardError as e:
form.add_error("Kortet ble ikke akseptert "+token)
Jquery
Stripe.setPublishableKey('pk_test_H1PZQA7ypCa8UIlEy6S9ovhE');
$( '#payment-form' ).submit(function(e){
$form = $(this);
$form.find('button').prop('disabled', true);
Stripe.card.createToken($form, function(status, response){
if(response.error){
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
}
else{
var token = response.id;
$form.find('input[id="id_token"]').val(token);
$('#id_token').val(token);
$form.get(0).submit();
}
});
return false;
});
Thank you for the help
Related
i created a normal django model.ModelForm and it is worked perfectly until i tried to add Progress bar for files uploading, i have an issue. i recieve the form information(request.POST and request.FILES) twice! but it is save the data only once in database, so also it is work, but i know i have a mistake in my code and i want to understand my mistake.
this is my function for displaying the progress bar:
function UploadFilesWithProgress(form, url) {
const progressbarWrap = document.querySelector('.progress-bar-wrap'),
label = progressbarWrap.querySelector('h6'),
percentage = progressbarWrap.querySelector('span'),
progressbarFill = progressbarWrap.querySelector('.progress > .progress-bar')
let xhr = new XMLHttpRequest()
xhr.open('POST', url, true);
xhr.upload.onloadstart = function (e) {
progressbarWrap.classList.remove('d-none')
percentage.textContent = '0%'
label.textContent = 'uploading...'
};
xhr.upload.onprogress = function (e) {
const percent = e.lengthComputable ? (e.loaded / e.total) * 100 : 0;
progressbarFill.style.width = percent.toFixed(2) + '%';
progressbarFill.setAttribute('aria-valuenow', percent.toFixed(2))
percentage.textContent = percent.toFixed(2) + '%';
}
xhr.upload.onloadend = function (e) {
label.textContent = 'uplaod completed!'
percentage.textContent = 'completed!'
}
xhr.send(new FormData(form));
}
Form = document.getElementById('add-course-form')
if (Form) {
Form.onsubmit = function () {
UploadFilesWithProgress(Form, Form.action);
}
}
and this is my view:
# I use CBV, so i share just the post method to not get missy.
def post(self, *args, **kwargs):
form = OfflineTutorialForm(
user=self.request.user.booth,
data=self.request.POST,
files=self.request.FILES
)
video_formset = AddOfflineVideoTutorialFormSet(
data=self.request.POST,
files=self.request.FILES
)
print(self.request.POST, self.request.FILES)
if form.is_valid() and video_formset.is_valid():
off_tutorial = form.save(commit=False)
off_tutorial.booth = self.request.user.booth
off_tutorial.save()
form.save_m2m()
video_off_tutorial = video_formset.save(commit=False)
for video in video_off_tutorial:
video.tutorial = off_tutorial
video.save()
return redirect('offline-tutorial')
return redirect('/')
It looks like you are uploading the data via form submit and ajax, you can prevent the form from submitting normally with event.preventDefault()
Form.onsubmit = function (event) {
event.preventDefault();
UploadFilesWithProgress(Form, Form.action);
}
I am sending some data from html template to views.py via ajax.From the id sent to views.py I am creating sql records. However I was wondering if there is any way to send data from views.py to template to notify that the data is added to sql.
code-
$('#tn1').click(function(){
var msg='';
alert('inside alert');
if ($('textarea#message') != "") {
var message = $('#notesarea').val();
alert(message);
msg=message;
}
$.ajax({
url: 'post_note',
data: {
'note': msg
},
success: function (data) {
alert(data)
}
});
views.py
def post_note(request,id):
post_id = request.GET['note']
print(post_id)
//sql insertion code,once its done i want to notify to the front end..print some alert message.
return render(request, './profile.html')
You should use something like JSONResponse in your view, then you data will appear in success function
success: function (data) {alert(data)}
You can do this using JQuery Ajax in the template and by creating an "API view" in your views.py that is basically just a regular view that returns a JSONResponse after checking to verify the request is Ajax. As an example of the "API" option, using JQuery:
In your views.py file (using the GET method which you should only use if the note is short, will fit into the URL bar, and if you don't have major security concerns, otherwise see the POST example at bottom):
from django.http import JsonResponse
def post_note_api(request):
data = {}
if request.GET.get('post_note', None) is not None:
post_note = request.GET.get('post_note')
# save the note and indicate success
data['result'] = True
data['message'] = "Note posted successfully"
...
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
In your urls.py:
...
path('/api/post_note/', post_note_api, name="post_note_api"),
...
In your template (if you are using the GET method):
<script type="text/javascript">
$("#tn1").click(function(){
var message = $("#myTextArea").val();
$.ajax({ url: '{% url 'post_note_api' %}?post_note=' + message,
type: "GET",
dataType: "json",
cache: false
}).done(function(data) {
if (data.result === true){
alert(data.message);
}
});
});
});
</script>
If you are using the POST method instead of GET (which is probably the better option here):
<script type="text/javascript">
$("#tn1").click(function(){
var csrfToken = $( "input[name='csrfmiddlewaretoken']");
var message = $("#myTextArea").val();
$.ajax({ url: '{% url 'post_note_api' %}',
type: "POST",
dataType: "json",
data: {'post_note':message, 'csrfmiddlewaretoken':csrfToken.val()},
cache: false
}).done(function(data) {
if (data.result === true){
alert(data.message);
}
});
});
});
</script>
For the POST method, in your view just change request.GET.get('post_note') ... to request.POST.get('post_note') ... like so:
from django.http import JsonResponse
def post_note_api(request):
data = {}
if request.POST.get('post_note', None) is not None:
post_note = request.POST.get('post_note')
# save the note and indicate success
data['result'] = True
data['message'] = "Note saved successfully"
...
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
When you are sending data via POST don't forget to pass along your CSRF token as in the example above. This assumes you have a form on the page you can get it from, otherwise you can use something like this to get it:
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;
}
var csrftoken = getCookie('csrftoken');
If you don't want to deal with the CSRF token, you can mark the view with the #csrf_exempt decorator and remove the 'csrfmiddlewaretoken' data element from the Ajax call in the template, but it may not be ideal or the most secure. An example of that:
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
#csrf_exempt()
def post_note_api(request):
...
Now, without knowing more, this is basically just pseudocode (plus I just wrote this off the top of my head so it may have errors). If you post more details I can update my answer, but I think this should get you started.
I have used below for sending data from HTML to views.py and then return a success response back to HTML. Hope this can be helpful:)
HTML Code:
<button class="button primary fit small" onclick="saveContent()">Save</button>
Javascript Code:
<script>
function saveContent(){
var code =editor.getSession().getValue();
var URL = "{% url 'save' %}";
var data = {'code': code};
$.post(URL, data, function(response){ // This is the main function that will help you
if(response === 'success'){ window.location.reload(); }
else{ alert('Error! :('); }
});
}
</script>
View.py:
def save_content(request):
if request.method == 'POST':
if 'code' in request.POST:
file_data = request.POST['code']
return HttpResponse('success')
I am working with stripe to build a donation form in python Django. Some donations are one-time and others are recurring. What I want to do is create a customer object with both types of charges, so we can gather mailing address, email address, etc for each donation.
The problem I am having, is I can process a one-time payment using the stripe token. But I can't figure out how to do it with a customer. This is what I have tried to so far. The error I receive is No such token: cus_asdfasdfasdf. Any idea what I'm doing wrong?
Javascript on donate.html page:
var stripe = Stripe('public_key');
var elements = stripe.elements();
var card = elements.create('card');
card.mount('#card-element');
// Create a token or display an error when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createPaymentMethod({
type: 'card',
card: card,
billing_details: {
email: 'my_email#gmail.com',
},
}).then(function(result) {
stripePaymentMethodHandler(result.PaymentMethod)
});
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripePaymentMethodHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var paymentMethodInput = document.createElement('input');
paymentMethodInput.setAttribute('type', 'hidden');
paymentMethodInput.setAttribute('name', 'paymentMethodToken');
paymentMethodInput.setAttribute('value', token);
form.appendChild(paymentMethodInput);
}
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
View in django:
from django.shortcuts import render
import stripe
from transcal.settings import STRIPE_SECRET_KEY
from .forms import DonateForm
stripe.api_key = STRIPE_SECRET_KEY
def donate(request):
if request.method == 'POST':
stripe.api_key = STRIPE_SECRET_KEY
# Get the payment token ID submitted by the form:
token = request.POST.get('stripeToken')
amount = request.POST.get('amount')
payment_method = request.POST.get('paymentMethodToken')
single_or_recurring = request.POST.get('single_or_recurring')
customer = stripe.Customer.create(
description="Customer for jenny.rosen#example.com",
name='Joe',
email='joe#gmail.com',
payment_method=payment_method
)
if single_or_recurring == 'recurring':
# charge subscription
stripe.Subscription.create(
customer=customer,
items=[
{
"plan": "my_plan_id",
},
],
expand=["latest_invoice.payment_intent"]
)
else:
# charge one time
stripe.Charge.create(
amount=amount,
currency='usd',
description='Example charge',
source=customer
)
return render(request, 'donate.html')
It looks like you are using Payment Methods here, and with these you will need to explicitly specify the Payment Method in addition to the Customer when creating a one-off transaction or a subscription.
You can get Payment Methods attached to a Customer with stripe.PaymentMethod.list
Specifically, for one-off charges made with Payment Methods, you must use the Payment Intent API to create a Charge instead of the Charge API. You can associate a Payment Intent with a Customer.
For your subscription call: when creating a Subscription with stripe.Subscription.create you will want to specify the customer AND default_payment_method (pm_xxxyyyzz) attached to the customer that you wish the subscription to charge.
I don't know how to append data to API in Flask from JS to Python without using a global list in Python route, which is causing all users to see same API info.
I have an ajax post request in my JS static file that allows a user to select an item and upon selecting that item it posts that data to Python route which then loads data and appends it to a global array. And then within the route I return the JSON list to the api. I am trying to figure out another way to do this because with this method first of all from my understanding global variables are God awful for this exact reason because all users can see the global api info.
// On load cart
window.onload = function wowzers(){
var array = [];
var sum = 0;
// Get Data
var xhr = new XMLHttpRequest();
xhr.open('GET', 'pricing/orders/' + username +'/api', true);
xhr.onload = function(){
var data = JSON.parse(this.response);
if(xhr.status >= 200 && xhr.status < 400){
for(x in data){
for(key in data[x]){
array.push(Number(data[x][key]));
sum+=Number(data[x][key]);
subtotal.innerHTML = sum;
row = cart.insertRow(-1);
// Delete Data
row.addEventListener('click', function deleterow(){
index = this.rowIndex;
$.post('pricing/orders/delete', {
delete_item: index
});
cart.deleteRow(index);
subtotal.innerHTML = sum-Number(cart.rows[index].cells[1].innerHTML);
});
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell1.innerHTML = key;
cell2. innerHTML = data[x][key];
cell3. innerHTML = "<button class='btn btn-danger'>Delete</button>"
}
}
console.log(sum);
}else{
console.log(error)
}
}
xhr.send()
}
//Dynamic Cart
for(x = 0; x < tablerows; x++){
table.rows[x].addEventListener('click', addCartItem);
}
function addCartItem(ev){
var array = [];
var sum = 0;
index = this.rowIndex;
equipmentCell = table.rows[index].cells[0];
priceCell = table.rows[index].cells[1];
equipmentName = equipmentCell.innerHTML;
equipmentPrice = priceCell.innerHTML;
// Post Data
$.post('/pricing/orders/' + username + '/api', {
javascript_data: JSON.stringify({[equipmentName]:equipmentPrice})
});
cartrow = cart.insertRow(-1);
// Delete Data
cartrow.addEventListener('click', function deleterow(){
index = this.rowIndex;
subtotal.innerHTML = sum-Number(cart.rows[index].cells[1].innerHTML);
$.post('pricing/orders/delete', {
delete_item: index
});
cart.deleteRow(index);
});
cell1 = cartrow.insertCell(0);
cell2 = cartrow.insertCell(1);
cell3 = cartrow.insertCell(2);
cell1.innerHTML= equipmentName;
cell2.innerHTML = equipmentPrice;
cell3.innerHTML = "<button class='btn btn-danger'>Delete</button>";
// Open Api information
var xhr = new XMLHttpRequest();
xhr.open('GET', 'pricing/orders/' + username +'/api', true);
xhr.onload = function(){
var data = JSON.parse(this.response);
if(xhr.status >= 200 && xhr.status < 400){
for(x in data){
for(y in data[x]){
array.push(Number(data[x][y]));
sum+=Number(data[x][y]);
subtotal.innerHTML = sum;
}
}
}else{
console.log(error);
}
}
xhr.send();
}
Route Logic
# ---------------------------------- USER CART API -----------------------------
#app.route('/pricing/orders/<user_name>/api', methods=['POST', 'GET'])
#login_required
def api(user_name):
user_name = current_user.username
if request.method == 'POST':
cart.append(json.loads(request.form["javascript_data"]))
return jsonify(cart)
# ---------------------------- DELETE ITEM IN CART ROUTE ----------------------------------
#app.route('/pricing/orders/delete', methods=['POST', 'GET'])
#login_required
def delete_item():
if request.method == 'POST':
print(cart[json.loads(request.form["delete_item"])])
cart.pop(json.loads(request.form["delete_item"]))
print(cart)
return jsonify({"whoa": "there"})
# ----------------------------- DISPLAY CART BADGE LENGTH---------------------------------
#app.context_processor
def inject_badge_length():
badge_length = len(cart)
return {'BADGE_LENGTH' : badge_length}
I'm hoping I can post data to Python route and then append particular data to API without global list so all users are only able to view their own data. I'm a beginner in the RESTFUL API arena, and just need pointing in the right direction.
It seems like you are running into an issue with storing data.
Most likely, you will want some type of ORM like SQLAlchemy to handle your data storage. It has a bit of a learning curve, but will make things much easier to manage in the long run.
form.html
<form action='/login/' method = 'post'>
{% csrf_token %}
<label>Email: (*)</label><input type='text' name='email' value='' /><br />
<label>Password: </label><input type='password' name='password' value='' /><br />
<input type='submit' name='submit' value='Log in' />
</form>
and views.py i use HttpResponse not render_to_response
def login(request):
success = False
message = ''
try:
emp = Employee.objects.get(email = request.POST['email'])
if emp.password == md5.new(request.POST['password']).hexdigest() :
emp.token = md5.new(request.POST['email'] + str(datetime.now().microsecond)).hexdigest()
emp.save()
info = serializers.serialize('json', Employee.objects.filter(email = request.POST['email']))
success = True
return HttpResponse(json.dumps({'success':str(success).lower(), 'info':info}))
else:
message = 'Password wrong!'
return HttpResponse(json.dumps({'success':str(success).lower(), 'message':message}), status = 401)
except:
message = 'Email not found!'
return HttpResponse(json.dumps({'success':str(success).lower(), 'message':message}), status = 401)
if use render_to_response, i just add RequestContext but HttpResponse, i don't know what to do.
i use Django 1.4
Where's my problem
=========================
My problem is sloved when I change the function that render the HTML :
def homepage(request):
return render_to_response('index.html')
to
def homepage(request):
return render_to_response('index.html', context_instance=RequestContext(request))
That's a stupid mistake... thanks...
If you are using ajax to send the form and have included jQuery, you have two possibilities:
Manually add the csrfmiddlewaretoken data to your POST request
Automate CSRF token handling by modifying jQuery ajax request headers
1. Manually add csrfmiddlewaretoken
var data = {
csrfmiddlewaretoken: $('#myForm input[name=csrfmiddlewaretoken]').val(),
foo: 'bar',
};
$.ajax({
type: 'POST',
url: 'url/to/ajax/',
data: data,
dataType: 'json',
success: function(result, textStatus, jqXHR) {
// do something with result
},
});
2. Automate CSRF token handling
jQuery(document).ajaxSend(function(event, xhr, settings) {
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 = jQuery.trim(cookies[i]);
// 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;
}
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
But: It is said that modifying the ajax request headers is bad practice. Therefore i'd go with solution number one.
Source: Cross Site Request Forgery protection: AJAX
The Django Documentations (CSRF DOC LINK) clearly explains how to enable it.
This should be the basic way of writing view with csrf token enabled..
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def form(request):
if request.method == 'GET':
#your code
context = {}
return render (request, "page.html", context )