How do I change this QuerySet to have this JSON data output - python

From my current query:
response_data = {}
response_data["medium"] = list(BuildingStructure.objects.filter(geom__intersects = getgeom_medium).values('brgy_locat').annotate(countmedium = Count('brgy_locat')))
response_data["high"] = list(BuildingStructure.objects.filter(geom__intersects = getgeom).values('brgy_locat').annotate(counthigh = Count('brgy_locat')))
response_data["low"] = list(BuildingStructure.objects.filter(geom__intersects = getgeom_low).values('brgy_locat').annotate(countlow = Count('brgy_locat')))
result = {}
for category in response_data.values():
for element in category:
key = element.pop('brgy_locat')
if key not in result: result[key] = {
"loc": key
}
result[key].update(element)
return HttpResponse(json.dumps(result), content_type = 'application/json')
The JSON output is this:
{
"Mabini": {
"counthigh": 3,
"loc": "Mabini",
"countmedium": 2,
"countlow": 25
},
"Barangay 12": {
"loc": "Barangay 12",
"countlow": 29
},
"Katugasan": {
"loc": "Katugasan",
"countlow": 3
}
}
But I wanted to have this output instead:
{
"0": {
"counthigh": 3,
"loc": "Mabini",
"countmedium": 2,
"countlow": 25
},
"1": {
"loc": "Barangay 12",
"countlow": 29
},
"2": {
"loc": "Katugasan",
"countlow": 3
}
}
I'm new to Django and Python, I tried looping and used a variable to be the index, but the output changes and I can't figure it out. Any help is appreciated.

Add another simple transformation of the result:
json_result = {str(i): v for i, v in enumerate(result.values())}
return HttpResponse(json.dumps(json_result), content_type='application/json')
UPDATE: The order of the keys in the dict is not guaranteed. But if you want to get the exact output of the JSON then you can use the collections.OrderedDict of the python 2.7:
from collections import OrderedDict
json_result = OrderedDict((str(i), v) for i, v in enumerate(result.values()))

Your output is changing because you are using dictionary to store the keys. Dictionaries don't keep the order of their elements (they are unordered), its better for you to use python lists instead when you want keep the order of the elements.
E.g.
results = []
#...
results.append(...)

Related

Having an issue parsing through this json in python

I have created a var that is equal to t.json. The JSON file is a follows:
{
"groups": {
"customerduy": {
"nonprod": {
"name": "customerduynonprod",
"id": "529646781943",
"owner": "cloudops#coerce.com",
"manager_email": ""
},
"prod": {
"name": "phishing_duyaccountprod",
"id": "241683454720",
"owner": "cloudops#coerce.com",
"manager_email": ""
}
},
"customerduyprod": {
"nonprod": {
"name": "phishing_duyaccountnonprod",
"id": "638968214142",
"owner": "cloudops#coerce.com",
"manager_email": ""
}
},
"ciasuppliergenius": {
"prod": {
"name": "ciasuppliergeniusprod",
"id": "220753788760",
"owner": "cia_developers#coerce.com",
"manager_email": "jarks#coerce.com"
}
}
}
}
my goal was to pars this JSON file and get value for "owner" and output it to a new var. Example below:
t.json = group_map
group_id_aws = group(
group.upper(),
"accounts",
template,
owner = group_map['groups']['prod'],
manager_description = "Groups for teams to access their product accounts.",
The error I keep getting is: KeyError: 'prod'
Owner occurs 4 times, so here is how to get all of them.
import json
# read the json
with open("C:\\test\\test.json") as f:
data = json.load(f)
# get all 4 occurances
owner_1 = data['groups']['customerduy']['nonprod']['owner']
owner_2 = data['groups']['customerduy']['prod']['owner']
owner_3 = data['groups']['customerduyprod']['nonprod']['owner']
owner_4 = data['groups']['ciasuppliergenius']['prod']['owner']
# print results
print(owner_1)
print(owner_2)
print(owner_3)
print(owner_4)
the result:
cloudops#coerce.com
cloudops#coerce.com
cloudops#coerce.com
cia_developers#coerce.com
You get a key error since the key 'prod' is not in 'groups'
What you have is
group_map['groups']['customerduy']['prod']
group_map['groups']['ciasuppliergenius']['prod']
So you will have to extract the 'owner' from each element in the tree:
def s(d,t):
for k,v in d.items():
if t == k:
yield v
try:
for i in s(v,t):
yield i
except:
pass
print(','.join(s(j,'owner')))
If your JSON is loaded in variable data, you can use a recursive function
that deals with the two containers types (dict and list) that can occur
in a JSON file, recursively:
def find_all_values_for_key(d, key, result):
if isinstance(d, dict):
if key in d:
result.append(d[key])
return
for k, v in d.items():
find_all_values_for_key(v, key, result)
elif isinstance(d, list):
for elem in d:
find_all_values_for_key(elem, key, result)
owners = []
find_all_values_for_key(data, 'owner', owners)
print(f'{owners=}')
which gives:
owners=['cloudops#coerce.com', 'cloudops#coerce.com', 'cloudops#coerce.com', 'cia_developers#coerce.com']
This way you don't have to bother with the names of intermediate keys, or in general the structure of your JSON file.
You don't have any lists in your example, but it is trivial to recurse through
them to any dict with an owner key that might "lurk" somewhere nested
under a a list element, so it is better to deal with potential future changes
to the JSON.

Count number of objects in list of dictionary where a key's value is more than 1

Given a list of dictionaries:
data = {
"data": [
{
"categoryOptionCombo": {
"id": "A"
},
"dataElement": {
"id": "123"
}
},
{
"categoryOptionCombo": {
"id": "B"
},
"dataElement": {
"id": "123"
}
},
{
"categoryOptionCombo": {
"id": "C"
},
"dataElement": {
"id": "456"
}
}
]
}
I would like to display the dataElement where the count of distinct categoryOptionCombo is larger than 1.
e.g. the result of the function would be an iterable of IDs:
[123]
because the dataElement with id 123 has two different categoryOptionCombos.
tracker = {}
for d in data['data']:
data_element = d['dataElement']['id']
coc = d['categoryOptionCombo']['id']
if data_element not in tracker:
tracker[data_element] = set()
tracker[data_element].add(coc)
too_many = [key for key,value in tracker.items() if len(value) > 1]
How can I iterate the list of dictionaries preferably with a comprehension? This solution above is not pythonic.
One approach:
import collections
counts = collections.defaultdict(set)
for d in data["data"]:
counts[d["dataElement"]["id"]].add(d["categoryOptionCombo"]["id"])
res = [k for k, v in counts.items() if len(v) > 1]
print(res)
Output
['123']
This approach creates a dictionary mapping dataElements to the different types of categoryOptionCombo:
defaultdict(<class 'set'>, {'123': {'B', 'A'}, '456': {'C'}})
Almost a one-liner:
counts = collections.Counter( d['dataElement']['id'] for d in data['data'] )
print( counts )
Output:
Counter({'123': 2, '456': 1})
No need for sets, you can just remember each data element's first coc or mark it as having 'multiple'.
tracker = {}
for d in data['data']:
data_element = d['dataElement']['id']
coc = d['categoryOptionCombo']['id']
if tracker.setdefault(data_element, coc) != coc:
tracker[data_element] = 'multiple'
too_many = [key for key,value in tracker.items() if value == 'multiple']
(If the string 'multiple' can be a coc id, then use multiple = object() and compare with is).

Pull key from json file when values is known (groovy or python)

Is there any way to pull the key from JSON if the only thing I know is the value? (In groovy or python)
An example:
I know the "_number" value and I need a key.
So let's say, known _number is 2 and as an output, I should get dsf34f43f34f34f
{
"id": "8e37ecadf4908f79d58080e6ddbc",
"project": "some_project",
"branch": "master",
"current_revision": "3rtgfgdfg2fdsf",
"revisions": {
"43g5g534534rf34f43f": {
"_number": 3,
"created": "2019-04-16 09:03:07.459000000",
"uploader": {
"_account_id": 4
},
"description": "Rebase"
},
"dsf34f43f34f34f": {
"_number": 2,
"created": "2019-04-02 10:54:14.682000000",
"uploader": {
"_account_id": 2
},
"description": "Rebase"
}
}
}
With Groovy:
def json = new groovy.json.JsonSlurper().parse("x.json" as File)
println(json.revisions.findResult{ it.value._number==2 ? it.key : null })
// => dsf34f43f34f34f
Python 3: (assuming that data is saved in data.json):
import json
with open('data.json') as f:
json_data = json.load(f)
for rev, revdata in json_data['revisions'].items():
if revdata['_number'] == 2:
print(rev)
Prints all revs where _number equals 2.
using dict-comprehension:
print({k for k,v in d['revisions'].items() if v.get('_number') == 2})
OUTPUT:
{'dsf34f43f34f34f'}

merge dictionaries and have one big dictionary within list

payload = [
{
"Beds:": "3"
},
{
"Baths:": "2.0"
},
{
"Sqft:": "1,260"
},
]
How would I have such list be like:
payload = [{'Beds':"3","Baths":"2.0","Sqft":"1,260"}]
instead of multiple dictionaries; I want one dictionary within the list.
Try this:
payload_new = [{i: j[i] for j in payload for i in j}]
This should help. Use the replace method to remove ":"
payload = [
{
"Beds:": "3"
},
{
"Baths:": "2.0"
},
{
"Sqft:": "1,260"
},
]
newDict = [{k.replace(":", ""): v for j in payload for k,v in j.items()}]
print newDict
Output:
[{'Beds': '3', 'Sqft': '1,260', 'Baths': '2.0'}]
Python 3 has built-in dictionary unfolding, try this
payload = {**payload_ for payload_ in payload}
To merge dictionaries in a big dictionary, you can write it this way:
payload={"Beds": 3 ,
"Baths": 2.0,
"Sqft": 1260
}
output:
>>>payload["Baths"]
2.0
views:
using [] was making it a array/list rather than a dictionary.
using "" on keys (e.g: "3") was making them strings instead of integers.

Defaultdict with Dict

I have a dictionary like this
a = [{'CohortList': [{'DriverValue': 0.08559936}, {'DriverValue': 0.08184596527051588}],
'_id': {'DriverName': 'Yield', 'MonthsOnBooks': 50, 'SegmentName': 'LTV110-Super Prime'}},
{'CohortList': [{'DriverValue': 2406.04329}, {'DriverValue': 2336.0058100690103}, ],
'_id': {'DriverName': 'ADB', 'MonthsOnBooks': 15, 'SegmentName': 'LTV110-Super Prime'}},
{'CohortList': [{'DriverValue': 2406.04329}, {'DriverValue': 2336.0058100690103}, ],
'_id': {'DriverName': 'ADB', 'MonthsOnBooks': 16, 'SegmentName': 'LTV110-Prime'}}]
I want to construct a list of dictionary with values as lists from the above dict set like this
{
"LTV110-Prime": [
{
"ADB": [
{
"16": 1500
}
]
},
{
"Yield": []
}
],
"LTV110-Super Prime": [
{
"ADB": [
{
"15": 1500
}
]
},
{
"Yield": [
{
"50": 0.09
}
]
}
]
}
Essentially, I want to group ADB and Yield for each segments with their values.
This is what I have done so far to achieve this target. The values for ADB are mean of DriverValue from CohortList list. I have used statistics.mean to find out the mean of the mapped values.
sg_wrap = defaultdict(dict)
for p in pp_data:
mapped = map(lambda d: d.get('DriverValue', 0), p['CohortList'])
dic = {p['_id']['MonthsOnBooks']: statistics.mean(mapped)}
print(p)
print(sg_wrap)
I am not able to append the Drivers to the inner dict. Please help.
Since you are wrapping everything into lists, you do not need a defaultdict(dcit) but a defaultdict(list).
The following seems to work:
result = defaultdict(list)
for entry in a:
id_ = entry["_id"]
name, months, segment = id_["DriverName"], id_["MonthsOnBooks"], id_["SegmentName"]
values = [x["DriverValue"] for x in entry["CohortList"]]
d = {name: [{months: statistics.mean(values)}]}
result[segment].append(d)
Result is
{'LTV110-Prime': [{'ADB': [{16: 2371.0245500345054}]}],
'LTV110-Super Prime': [{'Yield': [{50: 0.08372266263525793}]},
{'ADB': [{15: 2371.0245500345054}]}]}

Categories

Resources