Unable to resolve KeyError in Python using Flask - python

I continue to get this KeyError even though the key "name" obviously exists. I've attempted a couple methods to iterate through an array of dictionaries in Python with no luck. Any help is appreciated.
import re
from flask import Flask, json, request
from werkzeug.user_agent import UserAgent
app = Flask(__name__)
users = [
{"name:": "bitley",
"age": 5000,
"items": [
{"name:": "toyota"},
{"name": "camry"}
]
}
]
#/GET a user by ID
#app.route('/users/<string:name>')
def get_user_by_name(name):
#check to see if the user exists
for user in users:
if user['name'] == 'name':
return json.jsonify(users)
return json.jsonify({"message: " "user not found.."})
Error at line
if user['name'] == 'name':
KeyError: 'name'

It's because there is an extra colon "name:":.
What I think you mean is "name":.
And probably you mean return json.jsonify({"message:" "user not found.."}) instead of return json.jsonify({"message": "user not found.."}).
And if user['name'] == name: instead of if user['name'] == 'name':.

Your problem is when you create your users list, you have an extra colon in in the name key, it should be:
users = [
{"name": "bitley",
"age": 5000,
"items": [
{"name:": "toyota"},
{"name": "camry"}
]
}
]

The problem is not only the extra colon but also how you access the data in the list because, in list indices, you can only use integers or slices, not strings. Moreover, when you check the username, it should be a variable and not a string, otherwise, it will never pass through.
So it should be:
from flask import Flask, json, request
app = Flask(__name__)
users = [
{"name": "bitley",
"age": 5000,
"items": [
{"name:": "toyota"},
{"name": "camry"}
]
}
]
#app.route('/users/<string:name>')
def get_user_by_name(name):
#check to see if the user exists
for user in users:
if users[0]['name'] == name:
return json.jsonify(users)
return json.jsonify({"message: " "user not found.."})

Related

Python flask not working with url containing "?"

I am new to flask and I was trying to make GET request for url containing "?" symbol but it look like my program is just skipping work with it. I am working with flask-sql alchemy, flask and flask-restful. Some simplified look of my program looks like this:
fields_list = ['id']
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Get(Resource):
#staticmethod
def get():
users = User.query.all()
usr_list = Collection.user_to_json(users)
return {"Users": usr_list}, 200
class GetSorted(Resource):
#staticmethod
def get(field, type):
if field not in fields_list or type not in ['acs', 'desc']:
return {'Error': 'Wrong field or sort type'}, 400
users = db.session.execute(f"SELECT * FROM USER ORDER BY {field} {type}")
usr_list = Collection.user_to_json(users)
return {"Users": usr_list}, 200
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
api.add_resource(Get, '/api/customers')
Output with url "http://127.0.0.1:5000/api/customers?sort=id&sort_type=desc" looks like this
{
"Users": [
{
"Id": 1
},
{
"Id": 2
},
{
"Id": 3
},
]
}
But I expect it to look like this
{
"Users": [
{
"Id": 3
},
{
"Id": 2
},
{
"Id": 1
},
]
}
Somehow if I replace "?" with "/" in url everything worked fine, but I want it to work with "?"
In order to get the information after ?, you have to use request.args. This information is Query Parameters, which are part of the Query String: a section of the URL that contains key-value parameters.
If your route is:
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
Your key-values would be:
sort=<field>
sort_type=<type>
And you could get the values of the field and type keys like this:
sort = request.args.get('field', 'field_defaul_value')
sort_type = request.args.get('type', 'type_defaul_value')
More info:
1
2
With Flask you can define path variables like you did, but they must be part of the path. For example, defining a path of /api/customers/<id> can be used to get a specific customer by id, defining the function as def get(id):. Query parameters cannot be defined in such a way, and as you mentioned in your comment, you need to somehow "overload" the get function. Here is one way to do it:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
USERS = [
{"id": 1},
{"id": 3},
{"id": 2},
]
class Get(Resource):
#classmethod
def get(cls):
if request.args:
return cls._sorted_get()
return {"Users": USERS, "args":request.args}, 200
#classmethod
def _sorted_get(cls):
field = request.args.get("sort")
type = request.args.get("sort_type")
if field not in ("id",) or type not in ['acs', 'desc']:
return {'Error': 'Wrong field or sort type'}, 400
sorted_users = sorted(USERS, key=lambda x: x[field], reverse=type=="desc")
return {"Users": sorted_users}, 200
api.add_resource(Get, '/api/customers')
if __name__ == '__main__':
app.run(debug=True)
Here is Flask's documentation regarding accessing request data, and Flask-Restful's quickstart guide.

How to compare the json value with dictionary in python

I have JSON like this.
{
"currentdatetime": "11",
"syncinterval_seconds": 4,
"public_keys": [
{
"system": "aa",
"pubkey": "aa"
}
],
"users": [
{
"username": "user",
"user_id": "user",
"realname": "user_10",
"emailaddress": "test#gmail.com",
"accountenabled": false,
"mustchangepassword": false,
"passwordhash": "$E6gi",
"accesslevel": [
"WORKER"
],
"expiration": "2022-11-02T16:21:52",
"site_specific": false,
"symkey": "aaaa",
"privatekey": "aaa"
},
]
}
and I created a dictionary like this which maps usernames to their respective access level
user_access = {
"user": "WORKER",
"user2": "ADMIN",
"user3": "WORKER",
"user4": "GENERAL"
}
I am trying to verify in my API response json that the defined user has the correct access level.
I wrote a function like this
def LoadUserList(apijson)
for user_result in apijson[USERS]:
username = user_result[USER_NAME]
accesslevel = user_result[accesslevel]
if (user_result[USER_NAME] == 'user' AND user_result[accesslevel] == 'WORKER')
print "success"
else
print "not matching"
But the above code is not working as expected. I don't know how to compare the values in the JSON with the values in the dictionary. How do I fix my code so that it prints "success" for each user in the JSON that has a matching accesslevel value in the user_access dictionary?
Dictionaries in python have 2 ways of accessing values by some key.
via hard bracket indexers - apijson["users"]
via .get - apijson.get("users")
Note that both are case-sensitive and both are using quotes to pass the values as strings rather than variable names. USERS = "users"; apijson[USERS] would be fine as well but USERS would need to first be defined.
Additionally -
We love colons in python so def LoadUserList(apijson): and if <>:/else:
The keywords or/and are case-sensitive so your example AND -> and
Your example json structure has users[0].accesslevel as an array so your (corrected) user_result["accesslevel"] == 'WORKER' won't evaluate to True since user_result["accesslevel"] = ["WORKER"]
So with some corrections,
def LoadUserList(apijson):
for user_result in apijson["users"]:
username = user_result["username"]
accesslevel = user_result["accesslevel"]
user_accesslevel = user_access.get(username) # "WORKER"
if (username == 'user' and user_accesslevel in accesslevel):
print("success")
else:
print("not matching")
Assuming apijson is a dict, e.g., generated by applying json.loads() on API result:
def LoadUserList(apijson)
for user in apijson['users']:
username, accesslevel = user['username'], user['accesslevel']
if user_access.get(username) in accesslevel:
print(username, "success")
else
print(username, "not matching")

Save values from POST request of a list of dicts

I a trying to expose an API (if that's the correct way to say it). I am using Quart, a python library made out of Flask and this is what my code looks like:
async def capture_post_request(request_json):
for item in request_json:
callbackidd = item['callbackid']
print(callbackidd)
#app.route('/start_work/', methods=['POST'])
async def start_work():
content_type = request.headers.get('content-type')
if (content_type == 'application/json'):
request_json = await request.get_json()
loop = asyncio.get_event_loop()
loop.create_task(capture_post_request(request_json))
body = "Async Job Started"
return body
else:
return 'Content-Type not supported!'
My schema looks like that:
[
{
"callbackid": "dd",
"itemid": "234r",
"input": [
{
"type": "thistype",
"uri": "www.uri.com"
}
],
"destination": {
"type": "thattype",
"uri": "www.urino2.com"
}
},
{
"statusCode": "202"
}
]
So far what I am getting is this error:
line 11, in capture_post_request
callbackidd = item['callbackid']
KeyError: 'callbackid'
I've tried so many stackoverflow posts to see how to iterate through my list of dicts but nothing worked. At one point in my start_work function I was using the get_data(as_text=True) method but still no results. In fact with the last method (or attr) I got:
TypeError: string indices must be integers
Any help on how to access those values is greatly appreciated. Cheers.
Your schema indicates there are two items in the request_json. The first indeed has the callbackid, the 2nd only has statusCode.
Debugging this should be easy:
async def capture_post_request(request_json):
for item in request_json:
print(item)
callbackidd = item.get('callbackid')
print(callbackidd) # will be None in case of the 2nd 'item'
This will print two dicts:
{
"callbackid": "dd",
"itemid": "234r",
"input": [
{
"type": "thistype",
"uri": "www.uri.com"
}
],
"destination": {
"type": "thattype",
"uri": "www.urino2.com"
}
}
And the 2nd, the cause of your KeyError:
{
"statusCode": "202"
}
I included the 'fix' of sorts already:
callbackidd = item.get('callbackid')
This will default to None if the key isn't in the dict.
Hopefully this will get you further!
Edit
How to work with only the dict containing your key? There are two options.
First, using filter. Something like this:
def has_callbackid(dict_to_test):
return 'callbackid' in dict_to_test
list_with_only_list_callbackid_items = list(filter(has_callbackid, request_json))
# Still a list at this point! With dicts which have the `callbackid` key
Filter accepts some arguments:
Function to call to determine if the value being tested should be filtered out or not.
The iterable you want to filter
Could also use a 'lambda function', but it's a bit evil. But serves the purpose just as well:
list_with_only_list_callbackid_items = list(filter(lambda x: 'callbackid' in x, request_json))
# Still a list at this point! With dict(s) which have the `callbackid` key
Option 2, simply loop over the result and only grab the one you want to use.
found_item = None # default
for item in request_json:
if 'callbackid' in item:
found_item = item
break # found what we're looking for, stop now
# Do stuff with the found_item from this point.

How to return JSON objects (List of Dictionaries) in Flask API

Newbie here and stuck on returning some objects from JSON to my Flask API.
I have a list of dictionaries called data, you'll see in my code below. I need to check if the status_id is in the data. If it is, I have to display that user's name. How would I access a dictionary from a list? Or is my json not valid? I did use a linter to check and it passed the JSON test. I'm getting error: string indices must be integers. Which leads me to believe that since it's a list I'll need integers for the indexes.
Any help in the right direction would be great.
Here's my code:
#app.route("/status/<status_id>", methods=['GET'])
def get_status(status_id):
data = [{
"id": 5,
"name": "Meghan"
},
{
"id": 6,
"name": "Julia"
}
]
data_dump = json.dumps(data, indent=4)
if status_id in data_dump:
#find that status id and name and return it
return data_dump[status_id]['name']
else:
return "Not Found in Dictionary"
See below. A simplified version of the get_status function.
Pay attention to the HTTP status code (200 Vs. 404)
#app.route("/status/<status_id>", methods=['GET'])
def get_status(status_id):
data = [{
"id": 5,
"name": "Meghan"
},
{
"id": 6,
"name": "Julia"
}
]
name = None
for entry in data:
if entry['id'] == status_id:
name = entry['name']
break
if name is not None:
print('The name for status_id {} is {}'.format(status_id,name))
return name, 200
# or, if you want to return both use Flask jsonify and send a dict
# see http://flask.pocoo.org/docs/1.0/api/#flask.json.jsonify
else:
print('Can not find a name for status id {}'.format(status_id))
return "Not Found in Dictionary", 404
For me it seems like you want to return the name of the object where id == status_id. Is that right? Than you don't have to dump it to json. You can check if the status_id exists in the list with:
len(list(filter(lambda x: x['id'] == status_id, data))) == 1
Explanation:
list(filter(lambda x: x['id'] == status_id, data))
This filters your list of dictionaries to only have these dictionaries that have the matching id.
len(...) == 1
This checks if there is only and and exactly one object that has this id. If you want to return the name of exactly that dict you could write it like that:
matching_dict = list(filter(lambda x: x['id'] == status_id, data))
if len(matching_dict) == 1:
return matching_dict[0]['name']
And if you then want to return json (as a string). Then you have to call json.dumps() like json.dumps(matching_dict[0]) depending on whatever you want to do.
Edit: So putting all together it could look like that:
#app.route("/status/<status_id>", methods=['GET'])
def get_status(status_id):
data = [{
"id": 5,
"name": "Meghan"
},
{
"id": 6,
"name": "Julia"
}
]
matching_dict = list(filter(lambda x: x['id'] == status_id, data))
if len(matching_dict) == 1:
return json.dumps(matching_dict[0])
else:
return "Found zero or more than one in Dictionary"
Request: GET /status/5
Response: {"id":5, "name": "Meghan"}

Python: How to check for record with the same name as a function-defined query in a JSON file

I am trying to get a system set up where there is a file, students.json, that contains a list of students. The structure will be:
{
"username": {
"l_name": "Surname",
"f_name": "Forename"
}
}
and I want to be able to have a python function, registry() that lets you search for a student by username, then choose either l_name or f_name as the displayed variable. But first, I want to find out if the record in question even exists and if it doesn't, exit back into my top-level function.
try this
import json
json_string = '{ "username": { "l_name": "Surname", "f_name": "Forename" } }'
def registry(username, l_or_f , reg_json):
user = reg_json.get(username)
if user:
print(user.get(l_or_f))
else:
print('no username')
if __name__ == "__main__":
reg = json.loads(json_string)
registry('username','l_name',reg)
registry('username2', 'l_name', reg)

Categories

Resources