In a Django view you can access the request.GET['variablename'], so in your view you can do something like this:
myvar = request.GET['myvar']
The actual request.GET['myvar'] object type is:
<class 'django.http.QueryDict'>
Now, if you want to pass multiple variables with the same parameter name, i.e:
http://example.com/blah/?myvar=123&myvar=567
You would like a python list returned for the parameter myvar, then do something like this:
for var in request.GET['myvar']:
print(var)
However, when you try that you only get the last value passed in the url i.e in the example above you will get 567, and the result in the shell will be:
5
6
7
However, when you do a print of request.GET it seems like it has a list i.e:
<QueryDict: {u'myvar': [u'123', u'567']}>
Ok Update:
It's designed to return the last value, my use case is i need a list.
from django docs:
QueryDict.getitem(key)
Returns
the value for the given key. If the
key has more than one value,
getitem() returns the last value. Raises
django.utils.datastructures.MultiValueDictKeyError
if the key does not exist. (This is a
subclass of Python's standard
KeyError, so you can stick to catching
KeyError
QueryDict.getlist(key) Returns the
data with the requested key, as a
Python list. Returns an empty list if
the key doesn't exist. It's guaranteed
to return a list of some sort.
Update:
If anyone knows why django dev's have done this please let me know, seems counter-intuitive to show a list and it does not behave like one. Not very pythonic!
You want the getlist() function of the GET object:
request.GET.getlist('myvar')
Another solution is creating a copy of the request object... Normally, you can not iterate through a request.GET or request.POST object, but you can do such operations on the copy:
res_set = request.GET.copy()
for item in res_set['myvar']:
item
...
When creating a query string from a QueryDict object that contains multiple values for the same parameter (such as a set of checkboxes) use the urlencode() method:
For example, I needed to obtain the incoming query request, remove a parameter and return the updated query string to the resulting page.
# Obtain a mutable copy of the original string
original_query = request.GET.copy()
# remove an undesired parameter
if 'page' in original_query:
del original_query['page']
Now if the original query has multiple values for the same parameter like this:
{...'track_id': ['1', '2'],...} you will lose the first element in the query string when using code like:
new_query = urllib.parse.urlencode(original_query)
results in...
...&track_id=2&...
However, one can use the urlencode method of the QueryDict class in order to properly include multiple values:
new_query = original_query.urlencode()
which produces...
...&track_id=1&track_id=2&...
Related
From my views.py I doing this query:
var_query = DB.objects.filter(Q(user_id=str(request.user.id)) & Q(router_name='router1' )).values('router_type', 'router_ip')
Working because I get this result:
{'router1': set(['[{"router_type": "CISCO", "router_ip": "192.168.1.1"}]'])}
the type of var_query is: <class 'django.db.models.query.QuerySet'>
When I convert this with list()
converted = list(var_query)
and this error:
AttributeError: 'set' object has no attribute 'iteritems'
becasue when a convert this queryset to list is inserted this: set(['
How to convert to real list or dict so I can work with my key or value?
It's not really clear what your final aim is. But it seems like you are overcomplicating things unnecessarily. I would suggest simplifying your approach and just filter the queryset normally (note, it looks like these Q objects are also unnecessary here, you can just pass the args in directly).
var_query = DB.objects.filter(
Q(user_id=str(request.user.id)) & Q(router_name='router1')
)
The result will be a queryset object that implements the iterator protocol and can be iterated over normally like a list or list-like object. Then to work with the fields in the data that you seem to be interested in, you can just do something like:
var_query = DB.objects.filter(
Q(user_id=str(request.user.id)) & Q(router_name='router1')
)
for obj in var_query:
router_type = obj.router_type
router_ip = obj.router_ip
# ... do other stuff with your data.
You don't need to bother using values unless you really have a proper use case for it.
If you can supply more context we can refine a more accurate solution.
I am making a telegram chatbot and can't figure out how to take out the [{' from the output.
def tether(bot, update):
tetherCall = "https://api.omniexplorer.info/v1/property/31"
tetherCallJson = requests.get(tetherCall).json()
tetherOut = tetherCallJson ['issuances'][:1]
update.message.reply_text("Last printed tether: " + str (tetherOut)+" Please take TXID and past it in this block explorer to see more info: https://www.omniexplorer.info/search")
My user will see this as a response: [{'grant': '25000000.00000000', 'txid': 'f307bdf50d90c92278265cd92819c787070d6652ae3c8af46fa6a96278589b03'}]
This looks like a list with a single dict in it:
[{'grant': '25000000.00000000',
'txid': 'f307bdf50d90c92278265cd92819c787070d6652ae3c8af46fa6a96278589b03'}]
You should be able to access the dict by indexing the list with [0]…
tetherOut[0]
# {'grant': '25000000.00000000',
# 'txid': 'f307bdf50d90c92278265cd92819c787070d6652ae3c8af46fa6a96278589b03'}
…and if you want to get a particular value from the dict you can index by its name, e.g.
tetherOut[0]['txid']
# 'f307bdf50d90c92278265cd92819c787070d6652ae3c8af46fa6a96278589b03'
Be careful chaining these things, though. If tetherOut is an empty list, tetherOut[0] will generate an IndexError. You'll probably want to catch that (and the KeyError that an invalid dict key will generate).
I'm working with a Rest Api for finding address details. I pass it an address and it passes back details for that address: lat/long, suburb etc. I'm using the requests library with the json() method on the response and adding the json response to a list to analyse later.
What I'm finding is that when there is a single match for an address the 'FoundAddress' key in the json response contains a dictionary but when more than one match is found the 'FoundAddress' key contains a list of dictionaries.
The returned json looks something like:
For a single match:
{
'FoundAddress': {AddressDetails...}
}
For multiple matches:
{
'FoundAddress': [{Address1Details...}, {Address2Details...}]
}
I don't want to write code to handle a single match and then multiple matches.
How can I modify the 'FoundAddress' so that when there is a single match it changes it to a list with a single dictionary entry? Such that I get something like this:
{
'FoundAddress': [{AddressDetails...}]
}
If it's the external API sending responses in that format then you can't really change FoundAddress itself, since it will always arrive in that format.
You can change the response if you want to, since you have full control over what you've received:
r = json.parse(response)
fixed = r['FoundAddress'] if (type(r['FoundAddress']) is list) else [r['FoundAddress']]
r['FoundAddress'] = fixed
Alternatively you can do the distinction at address usage time:
def func(foundAddress):
# work with a single dictionary instance here
then:
result = map(func, r['FoundAddress']) if (type(r['FoundAddress']) is list) else [func(r['FoundAddress'])]
But honestly I'd take a clear:
if type(r['FoundAddress']) is list:
result = map(func, r['FoundAddress'])
else:
result = func(r['FoundAddress'])
or the response fix-up over the a if b else c one-liner any day.
If you can, I would just change the API. If you can't there's nothing magical you can do. You just have to handle the special case. You could probably do this in one place in your code with a function like:
def handle_found_addresses(found_addresses):
if not isinstance(found_addresses, list):
found_addresses = [found_addreses]
...
and then proceed from there to do whatever you do with found addresses as if the value is always a list with one or more items.
Summary: dictionary/json object indicates it does not have a given key (using either a hasattr call or a value in object.keys boolean test even though that key shows up in an object.keys() call. So how can I access the value for that key?
Longer version: I am quite puzzled trying to parse some json coming back from an API. When I try to determine whether the json object, which is showing up as a dictionary, has a given key, the code returns false for the key even when it shows the key is there for the object.
Here is how I am retrieving the json:
r = requests.get(url, headers = {'User-Agent':UA})
try:
print(r.json())
jsonobject = r.json()
print("class of jsonobject is %s"%jsonobject.__class__.__name__)
print("here are dictionary keys %s"%jsonobject.keys())
if hasattr(jsonobject, 'laps') and jsonobject['laps'] is not None:
...
else:
print("no laps object")
if hasattr(jsonobject, 'points') and jsonobject['points'] is not None:
...
The reason I am doing this is that often I am getting encoding errors from the field nested within the 'laps' array or the 'points' array so that I cannot insert the json data into a MongoDB database. I would like to delete these fields from the json object since they don't contain useful information anyway.
The problem is that the json object is always returning false for hasattr(jsonobject, 'laps') and hasattr(jsonobject,'points'. It returned false even in the case of a record where I then printed out the keys and they showed:
here are dictionary keys dict_keys(['is_peptalk_allowed', 'show_workout', 'hydration', 'records', 'include_in_stats', 'expand', 'pb_count', 'start_time', 'calories', 'altitude_max', 'hashtags', 'laps', 'pictures', 'duration', 'playlist'\
, 'sport', 'points', 'show_map', 'local_start_time', 'speed_avg', 'tagged_users', 'distance', 'altitude_min', 'is_live', 'author', 'feed_id', 'speed_max', 'id'])
So I thought perhaps the dict was behaving strangely with hasattr, and rewrote the code as:
if 'laps' in jsonobject.keys() and jsonobject['laps'] is not None:
but that also returns false even thoug hit again prints the same array of keys that does include 'laps'.
hasattr() is entirely the wrong tool to use. It tests for attributes, but dictionary keys are not attributes.
To test for keys, use the in test directly against the dictionary:
if 'lap' in jsonobject:
Calling jsonobject.keys() is redundant and creates a new dictionary view object.
It'll be true for your dictionary, but that's not the only thing you are testing for. Your test is:
if 'lap' in jsonobject and jsonobject['lap'] is not None:
That'll fail if 'lap' is a key but the value in the dictionary is None.
The above test can be more simply and compactly stated as:
if jsonobject.get('lap') is not None:
If None is a valid value, don't test for it; stick to just 'lap' in jsonobject.
I want to know if it's possible to get values from this query string?
'?agencyID=1&agencyID=2&agencyID=3'
Why I have to use a query string like this?
I have a form with 10 check boxes. my user should send me ID of news agencies which he/she is interested in. so to query string contains of multiple values with the same name. total count of news agencies are variable and they are loaded from database.
I'm using Python Tornado to parse query strings.
Reading the tornado docs, this seems to do what you want
RequestHandler.get_arguments(name, strip=True)
Returns a list
of the arguments with the given name.
If the argument is not present, returns an empty list.
The returned values are always unicode.
So like this
ids = self.get_arguments('agencyID')
Note that here i used get_arguments, there is also a get_argument but that gets only a single argument.
You can get the whole query with
query = self.request.query
>>> from urlparse import urlparse, parse_qs
>>> url = '?agencyID=1&agencyID=2&agencyID=3'
>>> parse_qs(urlparse(url).query)
{'agencyID': ['1', '2', '3']}
tornado.web.RequestHandler has two methods to get arguments:
get_argument(id), which will get the last argument with name 'id'.
get_arguments(id), which will get all arguments with name 'id' into a list even if there is only one.
So, maybe get_arguments is what you need.