Python-requests + Django changing the parameters structure in URL - python

Basicly, I've done with Python-requests and Django search feature through Google Books API with single q parameter (as shown in link below)
https://developers.google.com/books/docs/v1/using#WorkingVolumes
and after submiting form I'm getting list of dicts in json as I want with this single parameter, and I'm getting in json data where appers keyword "Hobbit" and URL looks like this
http://127.0.0.1:8000/api?books=hobbit
but when I'm trying to add special keywords provided by Google Books API like,
intitle, inauthor, inpublisher, subject, etc.
and trying to search for it I'm getting URL
http://127.0.0.1:8000/api?books=hobbit&intitle=&inauthor=&inpublisher=&isbn=&lccn=&oclc=
which only returns the data of single q parameter, because the correct URL for special keywords in Google Books API looks like this
https://www.googleapis.com/books/v1/volumes?q=flowers+inauthor:keyes+subject:somesubject
So as you see then correct URL got signs
+ against & and : against =
so the Correct URL that I want to get would look like this
http://127.0.0.1:8000/api?books=hobbit+intitle:something+inauthor:something+inpublisher:something+isbn:something+lccn:something+oclc:something
My question is how to change this structure to correct as Google books API require?
Tried to find this in python-requests docs but there are nothing about this
views.py
def api(request):
books = {
'intitle': 'intitle',
'inauthor': 'inauthor',
'inpublisher': 'inpublisher',
'subject': 'subject',
'isbn': 'isbn',
'lccn': 'lccn',
'oclc': 'oclc'
}
if 'books' in request.GET:
books = request.GET['books']
url = 'https://www.googleapis.com/books/v1/volumes?q=%s' % books
response = requests.get(url)
books = response.json()
print(type(books))
with open("data_file.json", "w") as write_file:
json.dump(books, write_file)
return render(request, 'books/api.html', {'books': books})

You will have to construct the query string manually. Assuming that your request will look like http://127.0.0.1:8000/api?books=hobbit&intitle=a&inauthor=b&inpublisher=c, you can construct the query string like this:
def api(request):
# ...
if 'books' in request.GET:
books = request.GET['books']
query_dict = request.GET.copy()
del query_dict['books']
query = '+'.join([books, *['{}:{}'.format(k, v) for k, v in query_dict.items()]])
url = 'https://www.googleapis.com/books/v1/volumes?q=' + query
# ...
The final google query requires books as the first parameter. So, we need to extract the books value from request.GET. Now, to get all other values, we need to delete the books key. But, request.GET is a QueryDict object, which is immutable. To convert it into a mutable object, request.GET.copy() can be used (which creates a mutable copy).

Related

How to include a variable in api call in python?

I am trying to implement a searchbar in django. I am getting the search input as movie_title from the html form. Now, how do i include it in my api call ? I tried with curly braces. Here's is the code
def searchbar(request):
if request.method == 'GET':
movie_title = request.GET.get('movie_title')
searched_movie = requests.get(
'http://www.omdbapi.com/?apikey=9a63b7fd&t={movie_title}')
You can create the url as an object using f-strings (one of the ways) and pass that to the get() method:
url = f'http://www.omdbapi.com/?apikey=9a63b7fd&t={movie_title}'
searched_movie = requests.get(url)
Note: You don't need to create a different object and can directly use:
searched_movie = requests.get(f'http://www.omdbapi.com/?apikey=9a63b7fd&t={movie_title}')
The above approach helps with readability when there are several dynamic attributes involved.
If you want to use { and } in your query string you can simply write
searched_movie = requests.get('http://www.omdbapi.com/?apikey=9a63b7fd&t={'+movie_title+'}')
Otherwise you can write
searched_movie = requests.get('http://www.omdbapi.com/?apikey=9a63b7fd&t='+movie_title)

Extract fields from a JSON in Python(Django)

Hello I am new to the python world, and I am learning, I am currently developing a WebApp in Django and I am using ajax for sending requests, what happens is that in the view.py I get a JSON, from which I have not been able to extract the attributes individually to send to a SQL query, I have tried every possible way, I appreciate any help in advance.
def profesionales(request):
body_unicode = request.body.decode('utf-8')
received_json = json.loads(body_unicode)
data = JsonResponse(received_json, safe=False)
return data
Data returns the following to me
{opcion: 2, fecha_ini: "2021-02-01", fecha_fin: "2021-02-08", profesional: "168", sede: "Modulo 7", grafico: "2"}
This is the answer I get and I need to extract each of the values ​​of each key into a variable
You can interpret this as dict.
for key in received_json:
print(key,received_json[key])
# do your stuff here
but if it's always a object with same keys (fixed keys), you can access directly:
key_data = received_json[key]

Passing objects through Flask URL's

I am working on a site using Flask that is pulling data from an API, processing it into JSON, and then dynamically loading it throughout the site as needed. I am having an issue with matching the URL appropriately while at the same time efficiently loading what data I need.
Here is my main file:
import requests
from flask import Flask, render_template
app = Flask(__name__)
url = 'https://omgvamp-hearthstone-v1.p.mashape.com/cards'
myHeaders={
"X-Mashape-Key": 'key-here',
"Accept": "application/json"
}
r = requests.get(url, headers=myHeaders)
cards = r.json()
badSets = ['Promo', 'Hall of Fame', 'Tavern Brawl', 'Hero Skins', ' Missions', 'Credits', 'System', 'Debug']
#app.route('/')
def index():
return render_template('index.html', cards=cards, badSets=badSets)
#app.route('/<setName>', methods=['GET'])
def set(setName):
return render_template('set.html', cards=cards, setName=setName, badSets=badSets)
#app.route('/<setName>/<cardName>', methods=['GET'])
def individualCard(setName, cardName):
return render_template('card.html', cards=cards, setName=setName, cardName=cardName, badSets=badSets)
First, I'd prefer to not have to pass each html page all of my data. Is there some way to pull only what is needed and ignore the rest?
Second, I would like to pass a dictionary object i.e.
if card['name'] == card[setName][--index--][cardName]:
pass card object to html page here
How could this be achieved, and is it possible without having to use a for-loop through all of my data?
I'm happy to load my html pages if needed.
Assuming the basic structure of your parsed json data looks like this (a dictionary with lists of dictionaries):
{
"Basic": [{"cardId": 4711, ...}, {"cardId": 4712, ...}, ...],
"Fancy": [...],
...
}
You could rewrite:
#app.route('/<setName>', methods=['GET'])
def set(setName):
cardset = cards.get(setName)
return render_template('set.html', cardset=cardset)
This extracts the card set we are looking for by the dictionary key, according to the assumed data structure above.
Then in the template, instead of cardName, pass the cardId and rewrite the other route:
#app.route('/<setName>/<cardId>', methods=['GET'])
def individualCard(setName, cardId):
cardset = cards.get(setName)
matches = [x for x in cardset if x['cardId'] == cardId]
card = matches[0]
return render_template('card.html', card=card)
This uses list comprehension to extract a list of matches (everything that has the cardId we are looking for) from our selected cardset, and should be a list with a single element. We return the first element to the template for rendering.
Now this obviously does not do any error checking, for example the dictionary key we passed might be wrong and not be found, the cardId might not be found, or more interestingly there might be more than one result for the cardId we passed.
But this would be the general idea on how to approach this.
Also note I've left out badSets for clarity in the example, I'm assuming this are card sets that are forbidden, or for testing purposes.
For this case, you'd want to check the dictionary key first before looking up the set, and show an error page or something maybe:
#app.route('/<setName>', methods=['GET'])
def set(setName):
if setName in badSets:
return render_template('error.html')
cardset = cards.get(setName)
return render_template('set.html', cardset=cardset)
Disclaimer: This is coming purely from memory and it is late, so there might be an error here or there...

Pyramid route matching and query parameters

I have a Pyramid web service, and code samples are as follows:
View declaration:
#view_config(route_name="services/Prices/GetByTicker/")
def GET(request):
ticker = request.GET('ticker')
startDate = request.GET('startDate')
endDate = request.GET('endDate')
period = request.GET('period')
Routing:
config.add_route('services/Prices/GetByTicker/', 'services/Prices/GetByTicker/{ticker}/{startDate}/{endDate}/{period}')
Now I know this is all screwed up but I don't know what the convention is for Pyramid. At the moment this works inasmuch as the request gets routed to the view successfully, but then I get a "Dictionary object not callable" exception.
The URL looks horrible:
#root/services/Prices/GetByTicker/ticker=APPL/startDate=19981212/endDate=20121231/period=d
Ideally I would like to be able to use a URL something like:
#root/services/Prices/GetByTicker/?ticker=APPL&startDate=19981212&endDate=20121231&period=d
Any Pyramid bods out there willing to take five minutes to explain what I'm doing wrong?
from you sample code, i think you use the URL Dispatch
so it should be like this
config.add_route('services/Prices/GetByTicker/', 'services/Prices/GetByTicker/')
then the URL like:
#root/services/Prices/GetByTicker/?ticker=APPL&startDate=19981212&endDate=20121231&period=d
will match it
--edit--
you don't have to use a name like "services/Prices/GetByTicker" for route_name,and you can get the GET params use request.params['key']
View declaration:
#view_config(route_name="services_Prices_GetByTicker")
def services_Prices_GetByTicker(request):
ticker = request.params['ticker']
startDate = request.params['startDate']
endDate = request.params['endDate']
period = request.params['period']
Routing:
config.add_route('services_Prices_GetByTicker', 'services/Prices/GetByTicker/')
The query string is turned into the request.GET dictionary. You are using parenthesis to call the dictionary instead of accessing items via the brackets. For a url such as
#root/services/Prices/GetByTicker/?ticker=APPL&startDate=19981212&endDate=20121231&period=d
request.GET['ticker'] # -> 'APPL' or an exception if not available
request.GET.get('ticker') # -> 'APPL' or None if not available
request.GET.get('ticker', 'foo') # -> 'APPL' or 'foo' if not available
request.GET.getall('ticker') # -> ['APPL'] or [] if not available
The last option is useful if you expect ticker to be supplied multiple times.
request.params is a combination of request.GET and request.POST where the latter is a dictionary representing the request's body in a form upload.
Anyway, the answer is that request.GET('ticker') syntactically is not one of the options I mentioned, stop doing it. :-)

picasa api - How to get a specific album with an album id?

How do I get a specific album from the picasa api?
Currently I am doing something like this:
def album(gd_client, album_id, user):
all_albums = albums(gd_client,user)
for album in all_albums:
if album.service_id == album_id:
return album
Which means I get all the albums and filter out the one I need.
But there must be an easier and more efficient way.
Thanks!
In Google Data Protocol version 2.0 there is experimental support for PartialResponse, which allows you to filter responses at the server by passing in a fields parameter.
Unfortunately only the Java API supports 2.0, but you can easily add it to the Python API yourself.
It looks like you want "entry" API. Here is how I can get AlbumEntry for a public album (do not want to deal with auth):
base = "https://picasaweb.google.com";
user = "101405741057659770470" # myself
albumid = "6333524051829767505"
# must be inside of a function to use locals()
url = "%(base)s/data/entry/api/user/%(user)s/albumid/%(albumid)s" % locals()
gd_client = gdata.photos.service.PhotosService()
entry = gd_client.GetEntry(url)
assert isinstance(entry, gdata.photos.AlbumEntry)
Similar in Java:
String baseURL = "https://picasaweb.google.com";
String userId = "101405741057659770470" // myself
String albumid = "6333524051829767505"
String albumUrl = String.format(
"%s/data/entry/api/user/%s/albumid/%s", baseURL, userId, albumId);
// myService is defined here: https://developers.google.com/picasa-web/docs/2.0/developers_guide_java
AlbumEntry entry = myService.getEntry(new URL(albumUrl), AlbumEntry.class, (DateTime) null /* modified since*/);

Categories