I'm a little new to Python and have been able to build a pretty nice application over here, but I've been spinning my wheels for a few hours here and I wanted to ask for a little help. Here's my loop where I'm adding to a dictionary:
for toast in checkin_toasts:
if toast['checkin_id'] not in toasts:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
}
else:
toasts[toast['checkin_id']] = toasts[toast['checkin_id']],{
'user_id': toast['user_id'],
'username': toast['username']
}
In my case, I currently have a total of three toasts for two different checkins. The above loop gives me this dictionary:
{8: ({'user_id': 1, 'username': 'shaunwo'}, {'user_id': 2, 'username': 'shaunwo2'}), 9: {'user_id': 1, 'username': 'shaunwo'}}
And then when I try to use it in my jinja form, it works as I would expect for checkin 8 with the two toasts, but it does not work for my checkin 9 that only has one toast. I found that if I manually tweak that dictionary a bit to this:
{8: ({'user_id': 1, 'username': 'shaunwo'}, {'user_id': 2, 'username': 'shaunwo2'}), 9: ({'user_id': 1, 'username': 'shaunwo'},)}
THAT works in my jinja form beautifully. But I don't know how to revise my for loop above accordingly to give me that kind of dictionary with the (,) around the single instance for checkin 9.
CodePudding user response:
You can use the dict.setdefault
method to initialize a non-existent key of a dict with a list so that it can be consistently appended with the desired sub-dict:
for toast in checkin_toasts:
toasts.setdefault(toast['checkin_id'], []).append({
'user_id': toast['user_id'],
'username': toast['username']
})
CodePudding user response:
The problem is that in one branch of the if
statement, you set toasts[toast['checkin_id']]
to a dictionary, while in the other you set it to a tuple of its previous value and a dictionary:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
}
vs.
toasts[toast['checkin_id']] = (
toasts[toast['checkin_id']],
{
'user_id': toast['user_id'],
'username': toast['username']
},
)
Meanwhile, your frontend is expecting a tuple (or list) of dictionaries, regardless of whether there's 1, 2 or more.
As @blhsing posted, you can achieve this by always making it a list and appending entries to it; that's probably the neatest solution.
However, to answer the question as asked, to make a tuple of one item, there's special syntax for that in Python; a trailing comma:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
},
If you prefer to make it more explicit, you can add parentheses:
toasts[toast['checkin_id']] = ({
'user_id': toast['user_id'],
'username': toast['username']
},)``
At that point, you'd also need to fix the other case to make a longer tuple rather than nesting it:
toasts[toast['checkin_id']] = toasts[toast['checkin_id']] ({
'user_id': toast['user_id'],
'username': toast['username']
},)
As in @blhsing's answer, you can also combine those two into one, using the .get()
method with a default to give you an empty tuple when adding the first toast:
toasts[toast['checkin_id']] = toasts.get(toast['checkin_id'], ()) ({
'user_id': toast['user_id'],
'username': toast['username']
},)
CodePudding user response:
It seems that you are aggregating the toasts into a tuple
if they have the same checkin_id
and return a dictionary with checkin_id
s as keys and toast tuples as values.
In this case, you could use collections.defaultdict
and aggregate the toasts with the same checkin_id
with a tuple
.
from collections import defaultdict
toasts = defaultdict(tuple)
for toast in checkin_toasts:
toasts[toast['checkin_id']] = ({
'user_id': toast['user_id'],
'username': toast['username']
}, )
Otherwise, you could recreate the tuple every time by yourself without the help of collections.defaultdict
.
This key point is to use the asterisk operator *
to unpack the existing tuple and append the new element for the tuple assignment.
for toast in checkin_toasts:
if toast['checkin_id'] not in toasts:
# Always create a new key with an empty tuple as its value if the key does not exist.
toasts[toast['checkin_id']] = tuple()
toasts[toast['checkin_id']] = *toasts[toast['checkin_id']], {
'user_id': toast['user_id'],
'username': toast['username']
}
# # Equals to
# toasts[toast['checkin_id']] = tuple(*toasts[toast['checkin_id']], {
# 'user_id': toast['user_id'],
# 'username': toast['username']
# })
I would suggest the first approach.