I'm working on a Django timesheet application and am having trouble figuring out how to include aggregate sums that equal zero. If I do something like:
entries = TimeEntry.objects.all().values("user__username").annotate(Sum("hours"))
I get all users that have time entries and their sums.
[{'username': u'bob' 'hours__sum':49}, {'username': u'jane' 'hours__sum':10}]
When I filter that by a given day:
filtered_entries = entries.filter(date="2010-05-17")
Anyone who didn't enter time for that day is excluded. Is there a way to include those users who's sums are 0?
Thanks
Maybe you could try the relationship the other way round - start with users, and link to entries:
User.objects.all().values("username").annotate(Sum("timeentry__hours"))
Does that work?
Related
I'm using Django with Postgres.
On a page I can show a list of featured items, let's say 10.
If in the database I have more featured items than 10, I want to get them random/(better rotate).
If the number of featured item is lower than 10, get all featured item and add to the list until 10 non-featured items.
Because the random takes more time on database, I do the sampling in python:
count = Item.objects.filter(is_featured=True).count()
if count >= 10:
item = random.sample(list(Item.objects.filter(is_featured=True))[:10])
else:
item = list(Item.objects.all()[:10])
The code above miss the case where there less than 10 featured(for example 8, to add 2 non-featured).
I can try to add a new query, but I don't know if this is an efficient retrive, using 4-5 queries for this.
The best solution I could find is this:
from itertools import chain
items = list(chain(Item.objects.filter(is_featured=True).order_by('?'), Item.objects.filter(is_featured=False).order_by('?')))[:10]
In this way, the order of the querysets are retained, but downside is that items becomes a list not a Queryset. You can see more details in this SO Answer. FYI: there are some fantastic solutions like using Q or pipe but they don't retain order of queryset.
SQL method: You can achieve that with an SQL statement like this:
SELECT uuid_generate_v4(), *
FROM table_name
ORDER BY NOT is_featured, uuid_generate_v4()
LIMIT 10;
Explain: The generated UUID should simulate randomness (for the purpose of e-commerce, this should suffice). While sorting the rows by NOT is_featured will put the is_featured rows on top; and automatically flow the rows down to 10 limits if it run out of featured items.
i come with this doubt abobt how to make a linked dates list based on existing objects, first of all i have a model with a DateTimeField which stores the date and hour that the object was added.
I have something like:
|pk|name|date
|1|name 1|2016-08-02 16:14:30.405305
|2|name 2|2016-08-02 16:15:30.405305
|3|name 3|2016-08-03 16:46:29.532976
|4|name 4|2016-08-04 16:46:29.532976
And i have some records with the same day but different hour, what i want is to make a list displaying only the unique days:
2016-08-02
2016-08-03
2016-08-04
And also because i'm using the CBV DayArchiveView i want to add a link to that elements to list them per day with a url pattern like this:
url(r'^archive/(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/$', ArticleDayArchiveView.as_view(), name="archive_day"),
The truth is that i don't have a clue of how to achieve that, can you help me with that?
Extracting unique dates
instances = YourModel.objects.all()
unique_dates = list(set(map(lambda x: x.date.strftime("%Y-%m-%d"), instances)))
About listing them, your url pattern looks ok. You need to define a view in order to retrieve them and wire up with that url.
UPDATE:
If you want to order them, just:
sorted_dates = sorted(unique_dates)
In a Django app, I have a queryset for a data model called Comment. This contains text comments left by users.
Imagine 'n' users commented. What's the fastest way to calculate what % of comments were left by which user?
Right now I'm thinking it's going to be:
Comment.objects.filter(commenter=<username>).count()/Comment.objects.count()
What do you suggest? My objective is to flag people who're commenting too much, in order to screen their accounts for possible spamming. I'd be running this query voluminously, hence the focus on performance.
You should avoid making one query for each user in your database. Instead you can just query the number of comments for each user (or even the top n commenters) with something like:
from django.db.models import Count
total_comments = Comment.objects.count()
# Fetch top 10 commenters, annotated with number of comments, ordered by highest first
User.objects.annotate(num_comments=Count('comment')).order_by('-num_comments')[:10]
for user in users:
percentage = user.num_comments / total_comments
This example assumes you have a User model that your Comment has a foreign key to.
The percentage of total comments doesn't actually matter if you are comparing relative numbers of comments.
I have a model which has two attributes: date and length and others which are not relevant. And I need to display list of sums of length for each day in template.
The solution I've used so far is looping day by day and creating list of sums using aggregations like:
for day in month:
sums.append(MyModel.objects.filter(date=date).aggregate(Sum('length')))
But it seems very ineffective to me because of the number of db lookups. Isn't there a better way to do this? Like caching everything and then filter it without touching the db?
.values() can be used to group by date, so you will only get unique dates together with the sum of length fields via .annotate():
>>> from django.db.models import Sum
>>> MyModel.objects.values('date').annotate(total_length=Sum('length'))
From docs:
When .values() clause is used to constrain the columns that are returned in the result set, the method for evaluating annotations is slightly different. Instead of returning an annotated result for each result in the original QuerySet, the original results are grouped according to the unique combinations of the fields specified in the .values() clause.
Hope this helps.
I have a Django model with a created timestamp and I'd like to get the counts of objects created on each day. I was hoping to use the aggregation functionality in Django but I can't figure out how to solve my problem with it. Assuming that doesn't work I can always fall back to just getting all of the dates with values_list but I'd prefer to give the work to Django or the DB. How would you do it?
Alex pointed to the right answer in the comment:
Count number of records by date in Django
Credit goes to ara818
Guidoism.objects.extra({'created':"date(created)"}).values('created').annotate(created_count=Count('id'))
from django.db.models import Count
Guidoism.objects \
# get specific dates (not hours for example) and store in "created"
.extra({'created':"date(created)"})
# get a values list of only "created" defined earlier
.values('created')
# annotate each day by Count of Guidoism objects
.annotate(created_count=Count('id'))
I learn new tricks every day reading stack.. awesome!
Use the count method:
YourModel.objects.filter(published_on=datetime.date(2011, 4, 1)).count()