I need to pass from AngularJS to python a JSON object. JSON structure would be:
{ "name": "Bob",
"address": "Springfield",
"cars": [
{ "model": "Renault C15", "year": "1965" },
...
{ "model": "Ford Ka", "year": "1998" } ]
}
This is a fragment of my AngularJS controller. All parameters are input from an HTML form (in this case the array "cars" has been created manually, to show you the way I have it programmed)
$scope.cars= [];
var car1 = { model: 'Renault C15', year: '1965' };
var car2 = { model: 'Ford Ka', year: '1998' };
$scope.cars.push(car1);
$scope.cars.push(car2);
...
$scope.newForm = function() {
var dataToSend= {
name: $scope.name,
address: $scope.address,
cars: $scope.cars
};
$http({
method: 'POST',
url: '/myUrl/something',
data: $.param(dataToSend),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
...
}
If I inspect the POST request I see the following parameters:
name Bob
address Springfield
cars[0][model] Renault C15
cars[0][year] 1965
cars[1][model] Ford Ka
cars[1][year] 1998
Initially, I will not know how many items will have the array "cars".
Now, this is the header of a python function. I know how to store the normal arguments but I don't know how to do the same thing with array "cars". I would store it as a python list or dictionary.
def something(self, **params):
...
name=params['name']
address=params['address']
...
How can I store the array?
I won't tell you about AngularJS part as it's out of my interest, but I can tell you about CherryPy. It is be much easier for you to send and process your data as application/json, so I suggest you to avoid application/x-www-form-urlencoded and search how to send JSON with your client library. With CherryPy, of course, you can handle both ways.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
}
}
class App:
#cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<head>
<title>CherryPy demo</title>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>
<script type='text/javascript'>
var data = {
"name": "Bob",
"address": "Springfield",
"cars": [
{ "model": "Renault C15", "year": "1965" },
{ "model": "Ford Ka", "year": "1998" }
]
};
$(document).ready(function()
{
$('#send-json').on('click', function()
{
$.ajax({
'type' : 'POST',
'dataType' : 'JSON',
'contentType' : 'application/json',
'url' : '/jsonin',
'data' : JSON.stringify(data),
'success' : function(response)
{
console.log(response);
}
});
});
$('#send-form').on('click', function()
{
$.ajax({
'type' : 'POST',
'dataType' : 'JSON',
'url' : '/formin',
'data' : data,
'success' : function(response)
{
console.log(response);
}
});
});
});
</script>
</head>
<body>
<p><a href='#' id='send-json'>Send JSON</a></p>
<p><a href='#' id='send-form'>Send form</a></p>
</body>
</html>
'''
#cherrypy.expose
#cherrypy.tools.json_out()
def formin(self, **kwargs):
# You can just print a variable a see it in the terminal
# where CherryPy is executed
print(kwargs)
# You would see
# {
# 'cars[1][year]': u'1998',
# 'name': u'Bob',
# 'cars[0][model]': u'Renault C15',
# 'address': u'Springfield',
# 'cars[0][year]': u'1965',
# 'cars[1][model]': u'Ford Ka'
# }
return kwargs.items()
#cherrypy.expose
#cherrypy.tools.json_in()
#cherrypy.tools.json_out()
def jsonin(self):
data = cherrypy.request.json # just the same structure
return data.items()
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
Related
I've got a Django website and I'm trying to integrate Stripe using Django the Stripe API on the backend and Vue.js on the frontend. However, when I try to run the checkout link that's supposed to redirect me to the payment processing page, I get the following error:
Error: IntegrationError: stripe.redirectToCheckout: You must provide one of lineItems, items, or sessionId.
at new r (https://js.stripe.com/v3/:1:6143)
at Js (https://js.stripe.com/v3/:1:165350)
at $s (https://js.stripe.com/v3/:1:165646)
at https://js.stripe.com/v3/:1:166758
at Qs (https://js.stripe.com/v3/:1:166769)
at nc (https://js.stripe.com/v3/:1:167275)
at Ec.redirectToCheckout (https://js.stripe.com/v3/:1:188030)
at http://localhost:8000/dashboard/myaccount/teams/plans/:342:39
Here's the Vue.js method responsible for this:
<script src="https://js.stripe.com/v3/"></script>
<script>
const PlansApp = {
data() {
return {
}
},
delimiters: ['[[', ']]'],
methods: {
subscribe(plan) {
console.log('Subscribe:', plan);
const stripe = Stripe('{{ stripe_pub_key }}');
fetch('/dashboard/myaccount/teams/api/create_checkout_session/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({
'plan': plan
})
})
.then(function(response) {
return response.json()
})
.then(function(session) {
console.log(session)
return stripe.redirectToCheckout({ sessionId: session.sessionId })
})
.then(function(result) {
if (result.error) {
console.log('Error:', result.error.message)
}
})
.catch(function(error) {
console.log('Error:', error);
});
}
}
}
Vue.createApp(PlansApp).mount('#plans-app')
</script>
And here's the Django code that creates the session on the backend:
#login_required
def create_checkout_session(request):
stripe.api_key = settings.STRIPE_SECRET_KEY
data = json.loads(request.body)
plan = data['plan']
if plan == 'basic':
price_id = settings.STRIPE_BASIC_PRICE_ID
else:
price_id = settings.STRIPE_PRO_PRICE_ID
try:
checkout_session = stripe.checkout.Session.create(
client_reference_id = request.user.userprofile.active_team_id,
success_url = '%s%s?session_id={CHECKOUT_SESSION_ID}' % (settings.WEBSITE_URL, reverse('team:plans_thankyou')),
cancel_url = '%s%s' % (settings.WEBSITE_URL, reverse('team:plans')),
payment_method_types = ['card'],
mode = 'subscription',
line_items = [
{
'price': price_id,
'quantity': 1
}
]
)
return JsonResponse({'sessionId': checkout_session['id']})
except Exception as e:
return JsonResponse({'error': str(e)})
I'm struggling to find out why I'm getting the error that I'm getting and would be grateful for any help!
I guest the problem come from the 'success_url' and the 'cancel_url'.
Try to add http:// or https:// in your url
Cordially
im trying use Django rest + angular 10, i will show a list of providers in the browser, could someone explain to me why my django api rest objects are not rendering? appear in console but not in html.
im using angular 10, django 2.7, cors, and my localhost.
this is my code.
// app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
const routes: Routes = [];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
//app.component.html
<div *ngFor='let provider of providers'>
<h2>{{ provider.name | uppercase }}</h2>
<p>{{ provider.procedence }}</p>
<p>{{ provider.email }}</p>
<p>{{ provider.telephone }}</p>
</div>
// app.component.ts
import { Component, OnInit } from '#angular/core';
import { ProviderService } from './provider.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'conexion';
providers: any[] = [];
constructor(
protected ProviderService: ProviderService
) {
}
ngOnInit() {
this.ProviderService.getProviders()
.subscribe(
(data) => { // Success
this.providers = data['results'];
console.warn(data)
},
(error) => {
console.error(error);
}
);
}
}
// app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpClientModule} from '#angular/common/http';
import { ProviderService } from './provider.service';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [ProviderService],
bootstrap: [AppComponent]
})
export class AppModule { }
// provider.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ProviderService {
constructor(protected http: HttpClient) { }
getProviders() {
return this.http.get('http://127.0.0.1:8000/provider?format=json');
}
}
To debug Use Async and learn how to use it, it's less code and less mistakes. Smart/Dumb components and OnPush Change Detection
Define
public providers$: Observable<any>;
ngOnInit
this.providers$ = this.ProviderService.getProviders();
Template
{{ providers$ | async | json }}
Currently using the django-carton app, I have a django view that returns JSON data that I use in an ajax call. Broadly speaking, I have got it working but struggling to work out how I can pass my item quantity (using ajax).
Within the template I can call my item quantities using:
{% for item in cart.items %}
{{ item.quantity }}
The ajax call connects to the view to return the Json data:
def cart_detail_api_view(request):
# cart_obj, new_obj = Cart.objects.new_or_get(request)
cart = Cart(request.session)
products = [{"name": x.name, "price": x.price} for x in cart.products]
cart_data = {"products": products, "total": cart.total}
return JsonResponse(cart_data)
This is my Jquery/Ajax call:
$(document).ready(function() {
var productForm = $(".form-product-ajax") // #form-product-ajax
productForm.submit(function(event) {
event.preventDefault();
// console.log("Form is not sending")
var thisForm = $(this)
//var actionEndpoint = thisForm.attr("action");
var actionEndpoint = thisForm.attr("data-endpoint");
var httpMethod = thisForm.attr("method");
var formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data) {
var submitSpan = thisForm.find(".submit-span")
if (data.added) {
submitSpan.html("In cart <button type='submit' class='btn btn-link'>Remove?</button>")}
var currentPath = window.location.href
if (currentPath.indexOf("") != -1) {
refreshCart()
}
},
error: function(errorData) {
console.log("error")
console.log(errorData)
}
})
})
function refreshCart() {
console.log("in current cart")
var cartTable = $(".cart-table")
var cartBody = cartTable.find(".cart-body")
// $(cartBody).empty()
var productRows = cartBody.find(".cart-product")
var cartTotal = cartTable.find(".cart-total-sec")
var currentUrl = window.location.href
var refreshCartUrl = '/api/cart/'
var refreshCartMethod = "GET";
var data = {};
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
success: function(data) {
console.log("success")
console.log(data)
if (data.products.length > 1) {
$(cartBody).empty()
productRows.html("")
$.each(data.products, function(index, value) {
console.log(value)
console.log(data.count)
cartBody.append("<tr><td>" + value.name + "</td><td>" + value.price + "</td></tr>")
})
cartTotal.find(".cart-total").text(data.total)
console.log(data.total)
} else {
window.location.href = currentUrl
}
},
error: function(errorData) {
console.log("error")
console.log(errorData)
}
})
}
})
You have to instruct your $.ajax() call that you are expecting data in JSON format, so the data is parsed properly in your success callback:
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
dataType: 'json', // <- here
success: function(data) {
// ...
},
error: function(errorData) {
// ...
}
})
I'm trying to upload a picture to my server with some additional data. My angularJs code is that:
function create_question(question, callback){
var form = new FormData()
var settings = {
"url": "http://127.0.0.1:8000/" + "question/api/create_question/",
"method": "POST",
"headers": {
'Content-Type': undefined
},
"processData": false,
"data": form
}
$cordovaFile.readAsDataURL(cordova.file.dataDirectory, question.name)
.then(function (success) {
form.append("file", success)
form.append("title", question.title)
form.append("options", JSON.stringify(question.options))
form.append("correct_option", question.correct_option)
form.append("question_id", question.question_id)
form.append("project_id", question.project_id)
$http(settings).then(function (response) {
if (response.data.hasOwnProperty("date_str")) {
callback(true, response.data)
console.log("succesFull")
} else {
console.log(JSON.stringify(response.data))
callback(false, response.data)
}
}, function (response) {
console.log(Utf8Decode(response.data))
callback(false, response.data)
});
// success
}, function (error) {
callback(false,error)
// error
});
}
In my server, I have that view:
#parser_classes((MultiPartParser, ))
class CreateQuestion(APIView):
def post(self, request, format=None):
picture = request.data['file']
question_id = request.data['question_id']
project_id = request.data['project_id']
options = request.data['options']
title = request.data['title']
correct_option = request.data['correct_option']
username = request.user.username
project = Project.objects.get(project_id=project_id)
if project.owner_user.username == username:
ext = '.jpg'
aws = AWSClient()
picture_name = question_id + ext
picture_url = aws.put(picture, 'question_pictures', picture_name)
question = Question.objects.create(question_id=question_id, title=title,
picture_url=picture_url, options=options, owner_project=project,
correct_option=correct_option)
project.question_count += 1
project.picture_url = picture_url
project.save()
serializer = QuestionSerializer(question, context={"request": request})
return JsonResponse(serializer.data)
else:
return JsonResponse({"result": "fail"})
After I made the request, question was created and the picture file was uploaded to Amazon S3. However, I could not open the resulting file in my pc. Where am I doing mistake?
After a long search on the internet, I found the answer. First, I read file with
$cordovaFile.readAsArrayBuffer(directory,filename)
After that, I created a Blob object with the file:
var imgBlob = new Blob([success], { type: "image/jpeg" } );
My final angularJS code is:
function create_question(question, callback){
var form = new FormData()
$cordovaFile.readAsArrayBuffer(cordova.file.dataDirectory, question.name)
.then(function (success) {
var imgBlob = new Blob([success], { type: "image/jpeg" } );
form.append("file", imgBlob)
form.append("title", question.title)
form.append("options", JSON.stringify(question.options))
form.append("correct_option", question.correct_option)
form.append("question_id", question.question_id)
form.append("project_id", question.project_id)
var settings = {
"url": "http://127.0.0.1:8000/" + "question/api/create_question/",
"method": "POST",
"headers": {
'Content-Type': undefined
},
"filename": question.id,
"processData": false,
"data": form,
"file": success,
"filename": "file"
}
$http(settings).then(function (response) {
if (response.data.hasOwnProperty("date_str")) {
callback(true, response.data)
console.log("succesFull")
} else {
console.log(JSON.stringify(response.data))
callback(false, response.data)
}
}, function (response) {
console.log(JSON.stringify(response.data))
callback(false, response.data)
});
// success
}, function (error) {
callback(false,error)
// error
});
}
I have this connection with ajax, I put a print in the formulario result and in the python in the bash I get the result from the select like this:
[{"pk": 1, "model": "pagoproveedores.test", "fields": {"just_a_test": "google"}}]
the problem is that when I want show it in the template it send me Server Response: undefined. Looks like I'm not getting the response from the view, I know I have the data that I need.
view.py
def ajax(request):
print 'inside ajax'
if request.POST.has_key('client_response'):
print 'inside if'
x = request.POST['client_response']
y = test.objects.filter(just_a_test=x)
formulario = serializers.serialize('json', y)
return HttpResponse(formulario, mimetype="application/json")
else:
return render_to_response('ajaxexample.html', context_instance=RequestContext(request))
Ajax.html
$(document).ready(function () {
$("#button").click(function () {
var input_string = $("#forminput").val();
$.ajax({
url: "/ajaxexample_json",
type: "POST",
dataType: "json",
data: {
client_response: input_string,
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function (json) {
$('#result').append('Server Response: ' + json.server_response);
},
error: function (xhr, errmsg, err) {
alert(xhr.status + ": " + xhr.responseText);
}
});
return false;
});
});
Instead
return HttpResponse(formulario, mimetype="application/json")
do
return HttpResponse(formulario, content_type="application/json")
I Fix it using this code and same view, ;)
$(document).ready(function () {
$("#button").click(function () {
var input_string = $("#forminput").val();
$.ajax({
url: "/ajaxexample_json",
type: "POST",
dataType: "json",
data: {
client_response: input_string,
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function (json) {
var jsonResponse = eval(json);
$.each(jsonResponse, function(index, element){
alert(JSON.stringify(jsonResponse));
$('#resultTables').append('<tr><td align="center">'+jsonResponse[0]["pk"]+'</td> <td align="center">'+jsonResponse[0]["fields"]["nombre_miembro_1"]+'</td> <td align="center"></td></tr>');
}); ;
},
error: function (xhr, errmsg, err) {
alert(xhr.status + ": " + xhr.responseText);
}
});
return false;
});
});