Question

I am running Django 1.4.3 and Python 2.7, with a PostgreSQL database (9.2.2). I have a model with a "last_view" field that is a timestamp of when a record is last viewed by a user. On my front page I want to display the ten most viewed items within the last week, so in my ListView I tried using this for my queryset:

startdate = timezone.now() - datetime.timedelta(days=7)
enddate = timezone.now()
urlpatterns = patterns('',
    url(r'^$',
        ListView.as_view(
            queryset=Tag.objects.filter(last_view__range=([startdate, enddate])).order_by('-views')[:10],
            context_object_name='most_viewed_list',
            template_name='tags/index.html'),
        name='index'),

This works when I first load the page. If I click any of the records and "view" them, the last_view attribute is updated in the database--but if I then reload the page, this item disappears from the "Recently Viewed" list (formed by the queryset described above).

I thought the problem was related to this post, where it seems like the "enddate" of timezone.now() is limited by when I start my server process. So when I click on a link after the server is running, the "current time" is in the future compared to "now()" and outside of the range (that is why the record I click disappears on a page reload). However, if I change things to just now as in the post mentioned above, I get an error on page load:

startdate = timezone.now - datetime.timedelta(days=7)
enddate = timezone.now

unsupported operand type(s) for -: 'function' and 'datetime.timedelta'

So I cannot create my startdate variable. I can get this to work by changing my queryset from _range to _gte, but it seems like that will break over time if now() is really timestamped to when the server process starts instead of "current time."

queryset=Tag.objects.filter(last_view__gte=(timezone.now() - datetime.timedelta(days=7)).order_by('-views')[:10]

The Django Tutorial on testing does show the use of now in making queries over dates, however they do not show how to subtract days from now or use it with timedelta or a date range...

Can someone please explain how to take a time difference from the actual, current time, i.e. using now instead of now()? I would also like to better understand the limitations of using now() versus now. I cannot find great documentation on this, since all examples I can find with timedelta() refer to timezone.now() or datetime.now(), which works (just not the way I want it to).

Thanks!

Was it helpful?

Solution

Subclass ListView and override the get_queryset method. By calculating the startdate and enddate inside the get_queryset method, timezone.now() will be the time when the request was made, not when the urls.py was initially loaded.

class TagListView(ListView):
    def get_queryset(self):
        startdate = timezone.now() - datetime.timedelta(days=7)
        enddate = timezone.now()
        return Tag.objects.filter(last_view__range=[startdate, enddate]).order_by('-views')[:10]
    context_object_name='most_viewed_list'
    template_name='tags/index.html'

urlpatterns = patterns('',
    url(r'^$', TagListView.as_view(), name='index'),
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top