I iterate through a nested dictionary taken from a json including one of the keys ("price") and sometimes a list sometimes a dictionary.
Data={"main": {"sub_main": [
{"id": "995", "item": "850", "price": {"ref": "razorback", "value": "250"}},
{"id": "953", "item": "763", "price": [{"ref": "razorback", "value": "450"},{"ref": "sumatra", "value": "370"},{"ref": "ligea", "value": "320"} ]},
]}}
I filter the result according to the value of another key ("id").
# here, the value of "price" key is a dict
result1 = [item["price"] for item in Data["main"]["sub_main"] if item["id"]=="995"]
# here, the value of "price" key is a list of dict
result2 = [item["price"] for item in Data["main"]["sub_main"] if item["id"]=="953"]
then I convert the result into a dictionary
#here I have what I wanted, because the "price" key is a dict
dresult={k:v for e in result1 for (k,v) in e.items()}
but when the "price" key has a dictionary list as its value, it doesn't work, because of course I get an error "'list' object has no attribute 'items'
#it cannot loop on the value and key because the "price" key is a list
dresult={k:v for e in result2 for (k,v) in e.items()}
how to make it convert the result to dictionary in both cases (because I'm iterating through thousands of data). how to dynamically do a type test and change to finally have a dictionary.I would like to use the result to display in a view in Django. I need it to be a dictionary
thank you.
CodePudding user response:
I hope I've understood your question right. In this code I distinguish if item['price']
is dict
/list
and create a new dict from ref
/value
keys:
Data = {
"main": {
"sub_main": [
{
"id": "995",
"item": "850",
"price": {"ref": "razorback", "value": "250"},
},
{
"id": "953",
"item": "763",
"price": [
{"ref": "razorback", "value": "450"},
{"ref": "sumatra", "value": "370"},
{"ref": "ligea", "value": "320"},
],
},
]
}
}
ids = "995", "953"
for id_ in ids:
out = {
d["ref"]: d["value"]
for item in Data["main"]["sub_main"]
for d in (
[item["price"]]
if isinstance(item["price"], dict)
else item["price"]
)
if item["id"] == id_
}
print(id_, out)
Prints:
995 {'razorback': '250'}
953 {'razorback': '450', 'sumatra': '370', 'ligea': '320'}
CodePudding user response:
so I made a function that you will pass id
of the sub_main dict you want and will give you price as a dictionary
def get_result(id_):
price= [item["price"] for item in Data["main"]["sub_main"] if item["id"]==id_][0]
match type(price).__name__:
case 'dict':return [price]
case 'list':return price
then to get result you pass the id as string
dresult=get_result('953')#[{'ref': 'razorback', 'value': '450'}, {'ref': 'sumatra', 'value': '370'}, {'ref': 'ligea', 'value': '320'}]
dresult=get_result('995')#[{'ref': 'razorback', 'value': '250'}]
how to render in view
in your view you can render the context as
return render(request, 'app_name/template_name.html',{'dictionaries': dresult})
reason behind
you can not a get many dictionaries unwrapped ie.{'ref': 'razorback', 'value': '450'}, {'ref': 'sumatra', 'value': '370'}, {'ref': 'ligea', 'value': '320'}
.and since your result seem to have a variable number of dicts so its better to wrap the single dict in a list so that in your template you can use
{% for dictionary in dictionaries %}:
{{ dictionary.ref}}#to get ref
{{ dictionary.value}}#to get value
...
{%endfor%}
edit:
override get_context_data
if its a detail or update view where you pass your pk
you can pass the pk to the get_result function like below
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['dictionaries'] = get_result(self.kwargs.get('pk'))
return context