How to QuerySet for Post per month - python

I have a model as such
class Post(models.Model):
submission_time = models.DateTimeField()
user = models.ForeignKey(User)
and I would like to have a queryset where it returns the number of Posts a user has made per month.
I have tried using ExtractMonth as so :
user.post_set.annotate(month_sub=ExtractMonth('submission_time')).values('month_sub').annotate(count=Count('month_sub'))
But its giving me a QuerySet like this :
<QuerySet [{'month_sub': 5, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}]>
Instead of one like this(Which i'd like to have) :
<QuerySet [{'month_sub': 5, 'count': 1}, {'month_sub': 6, 'count': 7}]>
Any Ideas on how to receive a queryset like so ?

You are quite close, the only thing you are missing is an .order_by('month_sub') (yeah, I know that sounds a bit strange). So you should write:
user.post_set.annotate(
month_sub=ExtractMonth('submission_time')
).values('month_sub').annotate(
count=Count('month_sub')
).order_by('month_sub')
This will result in query that looks like:
SELECT EXTRACT(MONTH FROM `post`.`submission_time`) AS `month_sub`,
COUNT(EXTRACT(MONTH FROM `post`.`submission_time`)) AS `count`
FROM `post`
WHERE `post`.`user_id` = 123
GROUP BY EXTRACT(MONTH FROM `post`.`submission_time`)
ORDER BY `month_sub` ASC
(where 123 should be replaced with the id of the user).
You can perhaps boost performance a tiny bit, by using Count('id'), although it is possible this has no (noticeable) impact:
user.post_set.annotate(
month_sub=ExtractMonth('submission_time')
).values('month_sub').annotate(
count=Count('id')
).order_by('month_sub')
If I run this on a sample database, I get:
<QuerySet [{'count': 273, 'month_sub': 1},
{'count': 172, 'month_sub': 2},
{'count': 565, 'month_sub': 3},
{'count': 59, 'month_sub': 4},
{'count': 452, 'month_sub': 5},
{'count': 550, 'month_sub': 6},
{'count': 622 'month_sub': 7},
{'count': 43, 'month_sub': 8},
{'count': 357, 'month_sub': 9},
{'count': 378, 'month_sub': 10},
{'count': 868, 'month_sub': 11},
{'count': 293, 'month_sub': 12}]>
(did some formatting to make it easier to inspect the result)

Related

Get unique elements in an array and add the value if same element is found - django

<QuerySet
[{'product': 6, 'quantity': 1},
{'product': 6, 'quantity': 10},
{'product': 7, 'quantity': 2},
{'product': 9, 'quantity': 3}]
>
how to get unique elements only in the array and add the quantity if same product is found. In the above eg: there are two "product: 6", so the new QuerySet should be
<QuerySet
[{'product': 6, 'quantity': 11},
{'product': 7, 'quantity': 2},
{'product': 9, 'quantity': 3}]
>

Python: Descending order and just 3 objects has a high value [duplicate]

This question already has answers here:
How do I sort a list of dictionaries by a value of the dictionary?
(20 answers)
Closed 6 months ago.
I have an array object like that, Not sort value, I want descending order and just 3 objects has a high value:
[{'id': 1, 'value': 3},
{'id': 2, 'value': 6},
{'id': 3, 'value': 8},
{'id': 4, 'value': 8},
{'id': 5, 'value': 10},
{'id': 6, 'value': 9},
{'id': 7, 'value': 8},
{'id': 8, 'value': 4},
{'id': 9, 'value': 5}]
I want result is descending order and just 3 objects have a high value, like this
[{'id': 5, 'value': 10},
{'id': 6, 'value': 9},
{'id': 7, 'value': 8},
{'id': 3, 'value': 8},
{'id': 4, 'value': 8},]
Please help me, thanks
t = [{'id': 1, 'value': 3},
{'id': 2, 'value': 6},
{'id': 3, 'value': 8},
{'id': 4, 'value': 8},
{'id': 5, 'value': 10},
{'id': 6, 'value': 9},
{'id': 7, 'value': 8}]
newlist = sorted(t, key=lambda d: d['value'])
newlist.reverse()
print(newlist[:3])
# [{'id': 5, 'value': 10}, {'id': 6, 'value': 9}, {'id': 7, 'value': 8}]
More info about list slicing
More info about reverse()
More info

How to get average from each hour in one week in django?

I have a task to get the average some data in each hour inside a week.
{'hour': 0, 'count': 70}
{'hour': 1, 'count': 92}
{'hour': 2, 'count': 94}
{'hour': 3, 'count': 88}
{'hour': 4, 'count': 68}
{'hour': 5, 'count': 69}
{'hour': 6, 'count': 70}
{'hour': 7, 'count': 82}
{'hour': 8, 'count': 91}
{'hour': 9, 'count': 67}
{'hour': 10, 'count': 92}
{'hour': 11, 'count': 100}
{'hour': 12, 'count': 92}
{'hour': 13, 'count': 55}
{'hour': 14, 'count': 61}
{'hour': 15, 'count': 47}
{'hour': 16, 'count': 36}
{'hour': 17, 'count': 19}
{'hour': 18, 'count': 11}
{'hour': 19, 'count': 6}
{'hour': 20, 'count': 3}
{'hour': 21, 'count': 9}
{'hour': 22, 'count': 27}
{'hour': 23, 'count': 47}
The data above is the result of this query
result = Device.objects.filter(station__in=stations, created_at__range=(start_date, end_date)) \
.extra({'hour': 'hour(created_at)'}) \
.values('hour').annotate(count=Count('id')).order_by('hour')
the result is queryed by 7 days range, what I want to do is get the average for each hour in 7 days, exampe the total of count in hour 0 is 70 then i need to average it from 7 days.
Any suggestion?
Probably you can try like this with F() expression:
from django.db.models import F, ExpressionWrapper, DecimalField
result = result.annotate(average=ExpressionWrapper(F('count')/7, output_field=DecimalField()))

Order a dictionary based on specific values

Before writing a function, I would like to be sure there is no pre-built (optimized) solution (like sorted()) that can:
From a dictionary like this one :
tags = {'pinoyako':{'likes': 119, 'comments': 11, 'count': 1}, 'dii':{'likes': 151, 'comments': 3, 'count': 1},'djiphantom3':{'likes': 127, 'comments': 6, 'count': 1}}
Order the keys based on 'likes', 'comments' or 'count'. If it's based on 'likes', the output should be a list ordered :
output = [['dii',151],['djiphantom3',127],['pinoyako',119]]
Use a generator expression within sorted() function with a proper key function:
In [22]: from operator import itemgetter
In [23]: sorted(((k, v['likes']) for k, v in tags.items()), key=itemgetter(1), reverse=True)
Out[23]: [('dii', 151), ('djiphantom3', 127), ('pinoyako', 119)]
You need more entries to illustrate. Check this:
tags = {'pinoyako':{'likes': 119, 'comments': 11, 'count': 1},
'pinoyako2':{'likes': 120, 'comments': 5, 'count': 2},
'djiphantom32':{'likes': 1275, 'comments': 61, 'count': 15},
'dii2':{'likes': 151, 'comments': 33, 'count': 13},
'dii':{'likes': 151, 'comments': 3, 'count': 1},
'djiphantom3':{'likes': 1275, 'comments': 61, 'count': 1}
}
tags_sorted = sorted(tags.items(), key=lambda x: (x[1]['likes'], x[1]['comments'], x[1]['count']))
tags_sorted
Output:
[('pinoyako', {'comments': 11, 'count': 1, 'likes': 119}),
('pinoyako2', {'comments': 5, 'count': 2, 'likes': 120}),
('dii', {'comments': 3, 'count': 1, 'likes': 151}),
('dii2', {'comments': 33, 'count': 13, 'likes': 151}),
('djiphantom3', {'comments': 61, 'count': 1, 'likes': 1275}),
('djiphantom32', {'comments': 61, 'count': 15, 'likes': 1275})]
Then you can do this:
tags_sorted = [[k, v['likes']] for k,v in tags_sorted]
tags_sorted
Output:
[['pinoyako', 119],
['pinoyako2', 120],
['dii', 151],
['dii2', 151],
['djiphantom3', 1275],
['djiphantom32', 1275]]

Convert dataframe to dictionary in Python

I have a csv file that I converted into dataframe using Pandas. Here's the dataframe:
Customer ProductID Count
John 1 50
John 2 45
Mary 1 75
Mary 2 10
Mary 5 15
I need an output in the form of a dictionary that looks like this:
{ProductID:1, Count:{John:50, Mary:75}},
{ProductID:2, Count:{John:45, Mary:10}},
{ProductID:5, Count:{John:0, Mary:15}}
I read the following answers:
python pandas dataframe to dictionary
and
Convert dataframe to dictionary
This is the code that I'm having:
df = pd.read_csv('customer.csv')
dict1 = df.set_index('Customer').T.to_dict('dict')
dict2 = df.to_dict(orient='records')
and this is my current output:
dict1 = {'John': {'Count': 45, 'ProductID': 2}, 'Mary': {'Count': 15, 'ProductID': 5}}
dict2 = [{'Count': 50, 'Customer': 'John', 'ProductID': 1},
{'Count': 45, 'Customer': 'John', 'ProductID': 2},
{'Count': 75, 'Customer': 'Mary', 'ProductID': 1},
{'Count': 10, 'Customer': 'Mary', 'ProductID': 2},
{'Count': 15, 'Customer': 'Mary', 'ProductID': 5}]
IIUC you can use:
d = df.groupby('ProductID').apply(lambda x: dict(zip(x.Customer, x.Count)))
.reset_index(name='Count')
.to_dict(orient='records')
print (d)
[{'ProductID': 1, 'Count': {'John': 50, 'Mary': 75}},
{'ProductID': 2, 'Count': {'John': 45, 'Mary': 10}},
{'ProductID': 5, 'Count': {'Mary': 15}}]

Categories