I want to be able to search a field for an artist/band from the lastfm api using flask and request. And I have problems in the syntax and/or logic but I don't know how to correct them.
from flask import Flask
from flask import render_template
from flask import request
import requests
import json
app = Flask(__name__)
app.debug = True
@app.route('/')
@app.route('/vista', methods=['GET', 'POST'])
def homepage():
params = {
'api_key': '5c1016ab26ab5b2f6ad21c3d873785bc',
'format' : 'json',
'artist': request.args.get('artista')
}
r = requests.get(
'http://ws.audioscrobbler.com/2.0/?method=artist.gettopalbums',
params=params)
return render_template('vista.html',
albums=r.json()['topalbums']['album'])
if __name__ == "__main__":
app.run (host = '127.0.0.1', port = 5000, threaded=True)
<form action="/buscador.py">
Artista: <input type="search" name="artista"><br>
<input type="submit" value="buscar">
</form>
It's not exactly clear what your problem is, but there are several errors in your code:
api_key
must be a string containing only hexadecimal digits, so the curly braces at the beginning and end are superfluous.artist
should be better within the sent parameters, and not within the URL, because what if the artist name contains spaces or non-ascii characters? It must be properly re-encoded to be a valid URL.requests
it takes care of it if you pass it to itparams
, but not if you put it in the URL with a simple concatenation.json.loads()
will break. For the response to come in JSON you must addparams
a fieldformat
with value"json"
.['topalbums']['album']
what it has is a list (it can have 50 elements!). If you want to get just the first one you need to set[0]
to select it (and then get its['name']
). It's not clear if your view (template) expects just an album or a list of them, but it['topalbums']['album']['name']
would fail anyway.Suppose that the template expects a list of albums and that it itself takes care of accessing the title using an y loop
album.name
or similar. This would then be the flask code:Note . To serve your client's request, you're having Flask make another web request. This request requires a time, during which your client will be waiting for the answer. But what's worse, since Flask is single-threaded and single-threaded, the entire server will be blocked until it
requests
returns the result, preventing it from serving more clients. It may be fine for testing, but for production you should deploy Flask viagunicorn
, for example, to support concurrency (while a client is waiting for its response, the server can attend to others).Update
The previous code, when used
request.args.get('artista')
to retrieve the artist to search for from the form, is implicitly expecting that artist to come to it as part of the URL (that is, to come to it in a request like this:GET /vista?artista=Coldplay
for example).However, a default HTML form makes a request
POST
and encodes the form parameters in a special way as part of the POST body and not in the URL, so the above code will not work.An easy way to fix this is to tell the browser that the form should make a request
GET
instead of a POST. So:Another possibility is to leave the FORM as it was (so it will use POST), and change the Flask part to get the artist's name like this:
second update
Since the user wants to use the same view to show both the FORM and its results (data that I had not understood correctly), it turns out that the same route may or may not carry the parameter
artista
, depending on whether it has been called as a mereGET /
or in response to the submit of the FORM.It is necessary to distinguish these cases in the code to avoid the request to the last.fm API if there is no
artista
search.The code would be like this:
The FORM must do a GET to the route
/vista
, so it should be like this: