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.
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 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
Using jsondump in python I need to send response to ajaxpage
object format in python shell show in below image
how to use the Java server object notation function to send response
//view output data
[<Userpost: Userpost object>, <Userpost: Userpost object>]
//this is my django view
def load_scroll_posts(request):
if request.method == 'POST':
post_id = request.POST['post_id']
loaded_posts = Userpost.objects.filter(id__gte = post_id)
return HttpResponse(json.dumps({'up':loaded_posts}))
//this is my ajax function
function load_remain_user_posts() {
var post_id = $(".message_box:last").attr("id");
var csrftoken = getCookie('csrftoken');
$.post('/theweber.in/load_m',{
post_id ':post_id,'
csrfmiddlewaretoken ':csrftoken},
function(data){
//console.log(data)
var obj = JSON.parse(data);
console.log(obj)
});
}
in console nothing displaying
Perhaps you mean to pass the two variables as parameters to your post? Something like:
function load_remain_user_posts() {
var post_id = $(".message_box:last").attr("id");
var csrftoken = getCookie('csrftoken');
var parameters = {
"post_id": post_id,
"csrfmiddlewaretoken": csrftoken
};
$.post('/theweber.in/load_m', parameters, function (data) {
//console.log(data)
var obj = JSON.parse(data);
console.log(obj)
});
}
I realised from my appengine log that the same cursor is being generated each time, the call to the Homehandler is made.
Please any idea what i am doing wrong, below is a snippet of my code:
class HomeHandler(webapp2.RequestHandler):
def get(self):
#page=self.request.get("page", default_value="1");
q = Allnews.query().order(-Allnews.date_added)
cursor = ndb.Cursor(urlsafe=self.request.get('cursor',default_value=None))
items, next_curs, more = q.fetch_page(30, start_cursor=cursor)
if more:
next_c = next_curs.urlsafe()
else:
next_c = None
context = { "news":items,"cursor":next_c}
# context["headlines"]=Feed.query(Feed.feed_cat.title == 'Headlines')
# context["gossip"] = Feed.query(Feed.feed_cat.title == 'Gossip')
# context["sports"] = Feed.query(Feed.feed_cat.title == 'Sports')
self.response.out.write(template.render('templates/homefeed.html',context))
this is the section of my homefeed.html template, I m using 'infinite scrolling' technique to fetch more results
<script>
{% if cursor %}
$(window).scroll(function()
{
var src=$("#src_val").val();
if($(window).scrollTop() == $(document).height() - $(window).height())
{
$('div#loadmoreajaxloader').show();
$.ajax({
url:"/home",
type:'GET',
data: {cursor: '{{cursor}}',feed_id:src },
success: function(news)
{
if(news)
{
$("#wrapper").append(news);
$('div#loadmoreajaxloader').hide();
}else
{
$('div#loadmoreajaxloader').html('No more posts to show.');
}
}
});
}
});
{% endif %}
</script>
It looks like you're using the get() method for both displaying a page and to handle an AJAX request. It's correctly generating a page with an initial cursor, but your $.ajax() method is expecting it to return JSON data.
Split the page request and AJAX request into two methods. Try adding a post() method to your HomeHandler that returns JSON data like this:
import json
def post(self):
q = Allnews.query().order(-Allnews.date_added)
cursor = ndb.Cursor(urlsafe=self.request.get('cursor',default_value=None))
items, next_curs, more = q.fetch_page(30, start_cursor=cursor)
if more:
next_c = next_curs.urlsafe()
else:
next_c = None
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(json.dumps({'news': items, 'cursor': next_c))
Now you have a method that returns JSON data to the AJAX request:
<script>
var cursor = null;
$(window).scroll(function()
{
if($(window).scrollTop() == $(document).height() - $(window).height())
{
$.ajax({
url:"/home",
type:'POST',
data: {cursor: cursor},
success: function(data)
{
$("#wrapper").append(data['news']);
cursor = data['cursor'];
if ( !cursor )
$('div#loadmoreajaxloader').show().html('No more posts to show.');
}
});
}
});
</script>
Notice how the cursor value is updated on each AJAX request. This is how you will get a new cursor on the next request.
(This code was not tested, you may need to debug it.)