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)
Related
I'll try to clarify what I mean.
Let's say I have this url:
https://test-api.com/users?age=17&sex=M
There's 2 fields: age and sex. The age field is required but the sex field is optional.
Let's say I want to make a bunch of tests and I use this code:
import requests
def testUserQuery(user_age, user_sex):
url = f'https://test-api.com/users?age={user_age}&sex={user_sex}'
response = requests.get(url)
test_query = testUserQuery(17)
Now, assuming that I can't go into the actual code of the API itself and change how empty fields are interpreted...
How can I make this test and leave the user_sex field blank?
In other words, is there a special universal symbol (like "&" which means "and" for every URL in the world) that I can put for user_sex that'll force the API to ignore the field and not cause errors?
Otherwise, I would have to do this:
import requests
def testUserQuery(user_age, user_sex=None):
if user_sex is None:
url = f'https://test-api.com/users?age={user_age}'
elif user_sex is not None:
url = f'https://test-api.com/users?age={user_age}&sex={user_sex}'
response = requests.get(url)
test_query = testUserQuery(17)
Imagine if I'm dealing with 10 optional fields. I don't think it would be very efficient to make multiple elif statements to change the URL for every single possible case where an optional field is empty.
I hope I'm being clear, sorry if this sounds confusing.
Here's a simple way to do this by utilising the params parameter:
import requests
URL = 'https://test-api.com/users'
def testUserQuery(**params):
return requests.get(URL, params=params)
testUserQuery(age=21, sex='male')
testUserQuery(age=21)
In other words, all you have to do is match the parameter names with those that are understood by the API. No need to manipulate the URL
One way to dynamically achieve this is by changing testUserQuery to accept its arguments as **kwargs then using urllib.parse.urlencode to dynamically build the query string.
from urllib.parse import urlencode
def testUserQuery(base_url='https://test-api.com/users', **kwargs):
params = urlencode({k: v for k, v in kwargs.items() if v is not None})
url = f"{base_url}{'?' + params if params else ''}"
print(url)
testUserQuery()
testUserQuery(a=1)
testUserQuery(a=1, b=2)
This outputs
https://test-api.com/users
https://test-api.com/users?a=1
https://test-api.com/users?a=1&b=2
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).
Which would be a better to way to get contents from two different request handlers?
This is how my app structure looks like
#/twitter/<query>
class TwitterSearch(webapp2.RequestHandler):
def get(self,query):
#get data from Twitter
json_data = data_from_twiiter()
return json_data
#/google/<query>
class GoogleSearch(webapp2.RequestHandler):
def get(self,query):
#get data from Twitter
json_data = data_from_google()
return json_data
Now I can access twitter search data and Google search data separately by calling their respective URL.
I also need to combine both these search results and offer to the user. What would be my best approach to do this ?
Should I call the get method of the respective classes like this ?
#/search/<query>
#Combined search result from google and twitter
class Search(webapp2.RequestHandler):
def get(self,query):
t = TwitterSearch()
twitterSearch = t.get(self,query)
g = GoogleSearch()
googlesearch = g.get(self,query)
Or fetch the data from URL using urllib or something like this ?
#/search/<query>
#Combined search result from google and twitter
class Search(webapp2.RequestHandler):
def get(self,query):
t = get_data_from_URL('/twitter/'+query)
g = get_data_from_URL('/google/'+query)
Or is there some other way to handle this situation?
You shouldn't make HTTP calls to your own application, that introduces a completely unnecessary level of overhead.
I would do this by extracting the query code into a separate function and calling it from both request handlers.
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. :-)
I'm new to python and would like some assistance.
I have a variable
q = request.GET['q']
How do I insert the variable q inside this:
url = "http://search.com/search?term="+q+"&location=sf"
Now I'm not sure what the convention is? I'm used to PHP or javascript, but I'm learning python and how do you insert a variable dynamically?
Use the format method of String:
url = "http://search.com/search?term={0}&location=sf".format(q)
But of course you should URL-encode the q:
import urllib
...
qencoded = urllib.quote_plus(q)
url =
"http://search.com/search?term={0}&location=sf".format(qencoded)
One way to do it is using urllib.urlencode(). It accepts a dictionary(or associative array or whatever you call it) taking key-value pairs as parameter and value and you can encode it to form urls
from urllib import urlencode
myurl = "http://somewebsite.com/?"
parameter_value_pairs = {"q":"q_value","r":"r_value"}
req_url = url + urlencode(parameter_value_pair)
This will give you "http://somewebsite.com/?q=q_value&r=r_value"
q = request.GET['q']
url = "http://search.com/search?term=%s&location=sf" % (str(q))
Use this it will be faster...