I am working on building a flight price search website as part of a project and have managed to get most of the functionality I require working.
Here's what the front-end looks like so far:
When users enter in the details, a POST request is sent to an API.
API: https://developers.amadeus.com/self-service/category/air/api-doc/flight-offers-search
API Python SDK: https://github.com/amadeus4dev/amadeus-python
I'm receiving a response from the API; however, am struggling to understand what I should then do with the information received. The next step is to pass the information from the API into a search results template and split out all of the received flight information, similar to how it is displayed on Sky Scanner:
Below is what I have in my views.py so far (currently passing in the whole response, in what I believe is JSON format?)
Views.py:
def flight_search(request):
kwargs = {'originLocationCode': request.POST.get('Origincity'),
'destinationLocationCode': request.POST.get('Destinationcity'),
'departureDate': request.POST.get('Departuredate'),
'returnDate': request.POST.get('Returndate'),
'adults': '1'}
try:
response = amadeus.shopping.flight_offers_search.get(
**kwargs)
print(response.data)
return render(request, "flightfinder/flight_search.html", {
"response": response
})
except ResponseError as error:
raise error
Here is an example response from the API:
{
"meta": {
"count": 2
},
"data": [
{
"type": "flight-offer",
"id": "1",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"lastTicketingDate": "2020-11-20",
"numberOfBookableSeats": 2,
"itineraries": [
{
"duration": "PT22H40M",
"segments": [
{
"departure": {
"iataCode": "GIG",
"terminal": "2",
"at": "2020-12-01T16:30:00"
},
"arrival": {
"iataCode": "CDG",
"terminal": "2E",
"at": "2020-12-02T07:45:00"
},
"carrierCode": "AF",
"number": "443",
"aircraft": {
"code": "77W"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT11H15M",
"id": "3",
"numberOfStops": 0,
"blacklistedInEU": false
},
{
"departure": {
"iataCode": "ORY",
"terminal": "2",
"at": "2020-12-02T17:10:00"
},
"arrival": {
"iataCode": "MAD",
"terminal": "2",
"at": "2020-12-02T19:10:00"
},
"carrierCode": "AF",
"number": "4792",
"aircraft": {
"code": "73H"
},
"operating": {
"carrierCode": "UX"
},
"duration": "PT2H",
"id": "4",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
},
{
"duration": "PT15H5M",
"segments": [
{
"departure": {
"iataCode": "MAD",
"terminal": "2",
"at": "2020-12-12T20:05:00"
},
"arrival": {
"iataCode": "CDG",
"terminal": "2F",
"at": "2020-12-12T22:20:00"
},
"carrierCode": "AF",
"number": "1101",
"aircraft": {
"code": "319"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT2H15M",
"id": "5",
"numberOfStops": 0,
"blacklistedInEU": false
},
{
"departure": {
"iataCode": "CDG",
"terminal": "2E",
"at": "2020-12-12T23:35:00"
},
"arrival": {
"iataCode": "GIG",
"terminal": "2",
"at": "2020-12-13T07:10:00"
},
"carrierCode": "AF",
"number": "442",
"aircraft": {
"code": "77W"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT11H35M",
"id": "6",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "USD",
"total": "2324.04",
"base": "2089.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "2324.04"
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": false
},
"validatingAirlineCodes": [
"AF"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "USD",
"total": "1311.52",
"base": "1194.00"
},
"fareDetailsBySegment": [
{
"segmentId": "3",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "O",
"includedCheckedBags": {
"quantity": 2
}
},
{
"segmentId": "4",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "J",
"includedCheckedBags": {
"quantity": 2
}
},
{
"segmentId": "5",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "L",
"includedCheckedBags": {
"quantity": 0
}
},
{
"segmentId": "6",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "R",
"includedCheckedBags": {
"quantity": 0
}
}
]
},
{
"travelerId": "2",
"fareOption": "STANDARD",
"travelerType": "CHILD",
"price": {
"currency": "USD",
"total": "1012.52",
"base": "895.00"
},
"fareDetailsBySegment": [
{
"segmentId": "3",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "O"
},
{
"segmentId": "4",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "J"
},
{
"segmentId": "5",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "L"
},
{
"segmentId": "6",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "R"
}
]
}
]
},
{
"type": "flight-offer",
"id": "2",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"lastTicketingDate": "2020-11-20",
"numberOfBookableSeats": 2,
"itineraries": [
{
"duration": "PT15H10M",
"segments": [
{
"departure": {
"iataCode": "GIG",
"terminal": "2",
"at": "2020-12-01T16:30:00"
},
"arrival": {
"iataCode": "CDG",
"terminal": "2E",
"at": "2020-12-02T07:45:00"
},
"carrierCode": "AF",
"number": "443",
"aircraft": {
"code": "77W"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT11H15M",
"id": "1",
"numberOfStops": 0,
"blacklistedInEU": false
},
{
"departure": {
"iataCode": "CDG",
"terminal": "2F",
"at": "2020-12-02T09:35:00"
},
"arrival": {
"iataCode": "MAD",
"terminal": "2",
"at": "2020-12-02T11:40:00"
},
"carrierCode": "AF",
"number": "1300",
"aircraft": {
"code": "319"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT2H5M",
"id": "2",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
},
{
"duration": "PT15H5M",
"segments": [
{
"departure": {
"iataCode": "MAD",
"terminal": "2",
"at": "2020-12-12T20:05:00"
},
"arrival": {
"iataCode": "CDG",
"terminal": "2F",
"at": "2020-12-12T22:20:00"
},
"carrierCode": "AF",
"number": "1101",
"aircraft": {
"code": "319"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT2H15M",
"id": "5",
"numberOfStops": 0,
"blacklistedInEU": false
},
{
"departure": {
"iataCode": "CDG",
"terminal": "2E",
"at": "2020-12-12T23:35:00"
},
"arrival": {
"iataCode": "GIG",
"terminal": "2",
"at": "2020-12-13T07:10:00"
},
"carrierCode": "AF",
"number": "442",
"aircraft": {
"code": "77W"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT11H35M",
"id": "6",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "USD",
"total": "2334.44",
"base": "2089.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "2334.44"
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": false
},
"validatingAirlineCodes": [
"AF"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "USD",
"total": "1316.72",
"base": "1194.00"
},
"fareDetailsBySegment": [
{
"segmentId": "1",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "O",
"includedCheckedBags": {
"quantity": 2
}
},
{
"segmentId": "2",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "J",
"includedCheckedBags": {
"quantity": 2
}
},
{
"segmentId": "5",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "L",
"includedCheckedBags": {
"quantity": 0
}
},
{
"segmentId": "6",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "R",
"includedCheckedBags": {
"quantity": 0
}
}
]
},
{
"travelerId": "2",
"fareOption": "STANDARD",
"travelerType": "CHILD",
"price": {
"currency": "USD",
"total": "1017.72",
"base": "895.00"
},
"fareDetailsBySegment": [
{
"segmentId": "1",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "O"
},
{
"segmentId": "2",
"cabin": "BUSINESS",
"fareBasis": "OS52OOND",
"brandedFare": "BUSINESS",
"class": "J"
},
{
"segmentId": "5",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "L"
},
{
"segmentId": "6",
"cabin": "ECONOMY",
"fareBasis": "RL50TCLD",
"brandedFare": "LIGHT3",
"class": "R"
}
]
}
]
}
],
"dictionaries": {
"locations": {
"MAD": {
"cityCode": "MAD",
"countryCode": "ES"
},
"GIG": {
"cityCode": "RIO",
"countryCode": "BR"
},
"CDG": {
"cityCode": "PAR",
"countryCode": "FR"
},
"ORY": {
"cityCode": "PAR",
"countryCode": "FR"
}
},
"aircraft": {
"77W": "BOEING 777-300ER",
"319": "AIRBUS A319",
"73H": "BOEING 737-800 (WINGLETS)"
},
"currencies": {
"USD": "US DOLLAR"
},
"carriers": {
"UX": "AIR EUROPA",
"AF": "AIR FRANCE"
}
}
}
My question is: how should I pass this information to the search results template so that I can populate the page with all of the flight information?
Should I pull out the information I need into lists and then pass these through to the template which displays the flight search results? (I'm not sure how I would then ensure the information pertained to a particular flight on the search results template)
Or should I simply pass the response and then extract the information from it on the template?
My apologies for the vague question here, please let me know if you require any additional information - I'm essentially stuck on how to handle this response and would really appreciate any guidance that anybody has.
Thank you!
I need to store values from response data (below) in variable.
Response Body:
{
"data": {
"packages": [
{
"object": "AAA",
"id": "BBB",
"code": "123",
"name": "Test8",
"description": "Test111",
"fee": "130.00 bath",
"productSeq": "3"
}, {
"object": "AAA",
"id": "CCC",
"code": "456",
"name": "Test9",
"description": "Test222",
"fee": "80.00 bath",
"productSeq": "2"
}, {
"object": "AAA",
"id": "CCC",
"code": "789",
"name": "Test10",
"description":"Test111",
"fee": "70.00 bath",
"productSeq": "1"
}
]
},
"resultCode": "20000",
"resultDesc": "Success",
"developerMessage": "Success"
}
If the id value of an object in the response is "CCC", I need to store that data like this, in a variable:
{
"object": "AAA",
"id": "CCC",
"code": "456",
"name": "Test9",
"description": "Test222",
"fee": "80.00 bath",
"productSeq": "2"
}, {
"object": "AAA",
"id": "CCC",
"code": "789",
"name": "Test10",
"description":"Test111",
"fee": "70.00 bath",
"productSeq": "1"
}
Can you help me create the script that would do that?
You can do it like this: -
var body = JSON.parse(responseBody)
var objArray = [];
for (i=0; i<body.data.packages.length;i++){
if (body.data.packages[i].id === "CCC"){
objArray.push(body.data.packages[i]);
}
}
postman.setEnvironmentVariable("varName", objArray)
I try to use a {json:api}-JSON with ember.js (1.13.3) and ember-data (1.13.4) by using the DS.JSONAPIAdapter.
The JSON:
{
"data": [
{
"type": "altersgruppe",
"id": "1",
"attributes": {
"name": "ALTER_21_24",
"tarifbeitraege": [
{
"type": "tarifbeitrag",
"id": "1",
"attributes": {
"name": "REISE",
"beitrag": "12.70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "2",
"attributes": {
"name": "KRANKEN",
"beitrag": "25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
}
]
}
},
{
"type": "altersgruppe",
"id": "2",
"attributes": {
"name": "ALTER_25_30",
"tarifbeitraege": [
{
"type": "tarifbeitrag",
"id": "3",
"attributes": {
"name": "REISE",
"beitrag": "29,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "4",
"attributes": {
"name": "KRANKEN",
"beitrag": "28,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "30.99"
}
}
]
}
}
]
}
The models:
App.Altersgruppe = DS.Model.extend({
name: DS.attr('string'),
tarifbeitraege: DS.hasMany('tarifbeitrag', {async: true})
});
App.Tarifbeitrag = DS.Model.extend({
altersgruppe: DS.belongsTo('altersgruppe'),
name: DS.attr('string'),
beitrag: DS.attr('string'),
proergaenzung: DS.attr('string'),
gesamtbeitrag: DS.attr('string')
});
When I used the ember-inspector to see the data only the model "altersgruppe" has records. The model "tarifbeitrag" has no records.
So why?
The adapter:
App.AltersgruppeAdapter = DS.JSONAPIAdapter.extend({
namespace: REST_ADAPTER_NAMESPACE,
shouldBackgroundReloadRecord: function(store, snapshot){
return false;
}
});
It seems to me that the "hasMany"-Relationship does not work. How to fix that. Any ideas (JSON wrong? Model wrong). Thank you.
Because of Mike1o1's tip to read the {json:api}-Spec again and I made the
decision to changed the structure of the JSON to this:
{
"data": [
{
"type": "altersgruppe",
"id": "1",
"attributes": {
"name": "ALTER_21_24"
},
"relationships": {
"tarifbeitraege": {
"data": [
{
"type": "tarifbeitrag",
"id": "1"
},
{
"type": "tarifbeitrag",
"id": "2"
}
]
}
}
},
{
"type": "altersgruppe",
"id": "2",
"attributes": {
"name": "ALTER_25_30"
},
"relationships": {
"tarifbeitraege": {
"data": [
{
"type": "tarifbeitrag",
"id": "3"
},
{
"type": "tarifbeitrag",
"id": "4"
}
]
}
}
}
],
"included": [
{
"type": "tarifbeitrag",
"id": "1",
"attributes": {
"name": "REISE",
"beitrag": "25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "2",
"attributes": {
"name": "KRANKEN",
"beitrag": "25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "3",
"attributes": {
"name": "REISE",
"beitrag": "29,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "4",
"attributes": {
"name": "KRANKEN",
"beitrag": "28,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "30.99"
}
}
]
}
This works with the DS.JSONAPIAdapter. Now in the ember-inspector I can see that the model "tarifbeitrag" has also records.
At first glance this doesn't look like a valid json-api response. tarifbeitraege should be a linked relationship, not embedded in the actual attributes of the data type. I don't believe json-api supports embedded attributes like that. Take a look at compound documents part of the spec for an example of what your json output should be.
My fixture data contains multiple array.Out of this multiple array cart_items contains some product data.
I am trying to calculate total no of products available in cart data (based on length of cart_items items) but i am not able to calculate no of items are present in cart_items.
In router i have selected application fixture as model for current route,as follow :
Astcart.IndexRoute = Ember.Route.extend({
model: function() {
return Astcart.Application.find();
}
});
Computed property code :
Astcart.IndexController = Ember.ArrayController.extend({
tot_cart_prd: function() {
return this.get("model.cart_items").get('length');
}.property("#each.isLoaded")
});
And my fixture data is :
Astcart.Application.adapter = Ember.FixtureAdapter.create();
Astcart.Application.FIXTURES = [
{
"logo_url": "img/logo.jpg",
"logged_in": {
"logged": true,
"username": "sachin",
"account_id": "4214"
},
"category_list": [
{
"id": "1",
"name": "Mobiles & Accessories"
},
{
"id": "2",
"name": "Computers & Software"
},
{
"id": "3",
"name": "Fashion"
},
{
"id": "4",
"name": "Electronics"
},
{
"id": "5",
"name": "Watches & Jewelry"
},
{
"id": "6",
"name": "Health & Beauty"
},
{
"id": "7",
"name": "Games"
},
{
"id": "8",
"name": "Books & Entertainment"
},
{
"id": "9",
"name": "Gaming"
},
{
"id": "10",
"name": "Shoes & Bags"
}
],
"cart_items": [
{
"id": "1",
"name": "Samsung Galaxy Tab 2",
"qty": "1",
"price": "1245.12",
"subtotal": "7842.23"
},
{
"id": "2",
"name": "Samsung Galaxy Tab 2",
"qty": "1",
"price": "1245.12",
"subtotal": "7842.23"
},
{
"id": "3",
"name": "Samsung Galaxy Tab 2",
"qty": "1",
"price": "1245.12",
"subtotal": "7842.23"
}
]
}
];
I have posted my code here(JSFiddle).
Can any one tell me why this.get("model.cart_items") is returning null?
Because your IndexController receive an array of Astcart.Application, from the route. You need to iterate in each application and get the length of each category list .
Your computed property need to be the following:
Astcart.IndexController = Ember.ArrayController.extend({
tot_cart_prd: function() {
var result = this.get('model').map(function(application) {
return application.get('category_list.length');
});
return result;
}.property('model.#each.category_list.length')
});
Here's an updated fiddle http://jsfiddle.net/marciojunior/PZZym/
I just looked at this and your core issue has something to do with the relationship setup between Application and Cart_items. The reason that this.get("model.cart_items").get('length') is failing is that this.get("model.cart_items") returns null. If you can get your relationship working you should be on the right track. I don't know anything about EmberModel, so I can't be of much help there.