How to query based on datetimeproperty in app engine - python

I have a bunch of posts:
PostModel(db.Model)
...
created = db.DateTimeProperty(auto_now = True)
and the postmodel.html for rendering each post had
{{p.created.strftime("%Y %m %d")}}
And eventually I want to sort the posts based on the time they were last modified by month. Would the query for, say all the posts created December of 2013, look something like
posts = PostModel.all().filter("created", 2013 12)
?

You could use the order method to add a sort order to the query.
For e.g. you can use the .order('-created') in a cascaded form to your above statement.

The argument to the filter for DatetimeProperty is a Datetime object.

Related

Django queryset - Filtering related table objects before aggregation

Consider this model in Django documentation:
Aggregation and Avg
There is a queryset like this:
Author.objects.annotate(average_rating=Avg('book__rating'))
which returns all authors annotated by average rate of all of their books.
What if I want to query authors annotated by average rate of their books which have been published for example in 2016.
Note that I want to get results with as few queries as possible.
Given that the Book model has an attribute pubdate which is a DateField, you can use:
from datetime import datetime
y2016 = datetime(2016,1,1)
Author.objects.filter(book__pubdate__lt=y2016) \
.annotate(average_rating=Avg('book__rating'))
So book__pubdate__lt means that you check that the pubdate of the book is less than (__lt) y2016 (the first of january 2016).
In case the filter is applied before the annotate it will filter the books away which are publised before 2016. Note that authors that have not publised before 2016 will not be in the resulting QuerySet. But this seems logical (since you can not calculate an average over an empty set).

Django day and month event date query

I have a django model that looks like this:
class Event(models.Model):
name = model.CharField(...etc...)
date = model.DateField(...etc...)
What I need is a way to get all events that are on a given day and month - much like an "on this day" page.
def on_this_day(self,day,month):
reutrn Events.filter(????)
I've tried all the regular date query types, but they all seem to require a year, and short of iterating through all years, I can't see how this could be done.
You can make a query like this by specifying the day and the month:
def on_this_day(day, month):
return Event.objects.filter(date__day=day, date__month=month)
It most likely scans your database table using SQL operators like MONTH(date) and DAY(date) or some lookup equivalent
You might get a better query performance if you add and index Event.day and Event.month (if Event.date is internally stored as an int in the DB, it makes it less adapted to your (day, month) queries)
Here's some docs from Django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#month

How to aggregate data only by the month part of a datetime field in Django

So my model is like this:
class Blog(models.Model):
title = models.CharField(max_length=100)
publication_date = models.DateField()
And now I want to get the count of the blog posts by each month. The raw sql would look like:
SELECT COUNT (*), EXTRACT(MONTH FROM publication_date) AS month FROM blog GROUP BY month;
One solution I found is here, it suggests that getting a date list first then loop through it using filter for each iteration. I do not like it, I am looking for a way to get the result without using loop.
You could use something to the effect of Blog.objects.filter(publication_date__range=[start_of_month, end_of_month]) to get all items from between those two dates. See range for details.

How do I get each distinct 'year' value out of a Django model with a datetime field?

I can successfully filter by a given year in my Django model, but I'm having trouble finding a way to list valid years so a user can access them.
I have a django model with a defined 'datetime' field, oh-so-originally named 'date'. In my templates, I can successfully access the 'bar.date.date.year' field, so I know it exists, but when I try the following function...
blog_years=[]
for entry in blog_entries:
if entry.date.date.year not in blog_years:
blog_years.append(entry.date.date.year)
I'm told that "'builtin_function_or_method' object has no attribute 'year'"
I can only assume I"m tripping over some aspect of Python I'm not familiar with, but I can't figure out what it is. I'm quite certain it has to be syntactical, but past that...
Django has an elegant and efficient way of doing this. You can check from their docs https://docs.djangoproject.com/en/3.0/ref/models/querysets/#dates
But to go over it
Entry.objects.dates('pub_date', 'year')
This will bring out distinct year values in the query.
if you are using postgres, you can do
BlogEntry.objects.extra(select={"year": "EXTRACT(YEAR FROM date)"}).distinct().values_list("year", flat=True)
A Python set does not allow duplicates, so if you wanted a list of distinct years:
blog_years = list(set([entry.date.year for entry in blog_entries]))
Or, you could use distinct():
blog_years = blog_entries.distinct(entry__date__year).values(entry__date__year)
Of course, adjust the above based on your model.
The first .date accesses a datetime object.
The second .date is accessing a method on datetime objects that returns a date object but not calling it (this step is unneccessary).
The last part (the way you wrote it) is trying to access the year attribute of the date method, instead of accessing the year attribute of the result of the date method call.
Correcting the code to see the difference, it would look like this...
blog_years=[]
for entry in blog_entries:
if entry.date.date().year not in blog_years:
blog_years.append(entry.date.date().year)
But what you should do is more like this...
blog_years=[]
for entry in blog_entries:
if entry.date.year not in blog_years:
blog_years.append(entry.date.year)
since datetime objects have the date attribute as well.
date() is a method of datetime, use
blog_years=[]
for entry in blog_entries:
if entry.date.date().year not in blog_years:
blog_years.append(entry.date.date().year)
from django 1.10 it has become very simple
from django.db.models.functions import ExtractYear
blog_years= blog_entries.annotate(
year=ExtractYear('created_on')
).values_list('year', flat=True)
blog_years = sorted(set(blog_years), reverse=True)
It might not be what you exactly expects (it can return years without blog posts):
from datetime import date
from django.db.models import Min
def blog_years():
current_year = date.today().year
queryset = Entry.objects.annotate(Min('date')).order_by('date')
if queryset:
oldest_year = queryset[0].date.date().year
else:
oldest_year = current_year
return range(oldest_year, current_year + 1)
ModelName.objects.dates('column_name', 'year')

Django - SQL Query - Timestamp

Can anyone turn me to a tutorial, code or some kind of resource that will help me out with the following problem.
I have a table in a mySQL database. It contains an ID, Timestamp, another ID and a value. I'm passing it the 'main' ID which can uniquely identify a piece of data. However, I want to do a time search on this piece of data(therefore using the timestamp field). Therefore what would be ideal is to say: between the hours of 12 and 1, show me all the values logged for ID = 1987.
How would I go about querying this in Django? I know in mySQL it'd be something like less than/greater than etc... but how would I go about doing this in Django? i've been using Object.Filter for most of database handling so far. Finally, I'd like to stress that I'm new to Django and I'm genuinely stumped!
If the table in question maps to a Django model MyModel, e.g.
class MyModel(models.Model):
...
primaryid = ...
timestamp = ...
secondaryid = ...
valuefield = ...
then you can use
MyModel.objects.filter(
primaryid=1987
).exclude(
timestamp__lt=<min_timestamp>
).exclude(
timestamp__gt=<max_timestamp>
).values_list('valuefield', flat=True)
This selects entries with the primaryid 1987, with timestamp values between <min_timestamp> and <max_timestamp>, and returns the corresponding values in a list.
Update: Corrected bug in query (filter -> exclude).
I don't think Vinay Sajip's answer is correct. The closest correct variant based on his code is:
MyModel.objects.filter(
primaryid=1987
).exclude(
timestamp__lt=min_timestamp
).exclude(
timestamp__gt=max_timestamp
).values_list('valuefield', flat=True)
That's "exclude the ones less than the minimum timestamp and exclude the ones greater than the maximum timestamp." Alternatively, you can do this:
MyModel.objects.filter(
primaryid=1987
).filter(
timestamp__gte=min_timestamp
).exclude(
timestamp__gte=max_timestamp
).values_list('valuefield', flat=True)
exclude() and filter() are opposites: exclude() omits the identified rows and filter() includes them. You can use a combination of them to include/exclude whichever you prefer. In your case, you want to exclude() those below your minimum time stamp and to exclude() those above your maximum time stamp.
Here is the documentation on chaining QuerySet filters.

Categories

Resources