Django querying on range of days with timezone.now and __range broken? - python

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!

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'),
)

Related

Render date for yesterday with a link

I have a workspace where users can add note, they can pick a date
I am trying to create 2 links, one for yesterday, one for tomorrow.
Right now I am using a calendar and it is fine, but I would like to create 2 quick links that send them to the note for yesterday.
So i have a code like that :
def WorkspaceYesterday(request):
yesterday = datetime.now() - timedelta(days=1)
yesterday.strftime('%m%d%y')
But i dont know how to render it in my template with a link.
Thank you
# you just need to render the context 'yesterday' to your template from your function
from django.shortcuts import render
def WorkspaceYesterday(request):
yesterday = datetime.now() - timedelta(days=1)
yesterday = yesterday.strftime('%m%d%y')
render(request, 'index.html', {'yesterday': yesterday})
# In your template index.html
<p>{{ yesterday }}</p>

Working with several time zone in Django

The application I am working on has as target users USA. And (as you may know) in USA there's more than one time zone. So I have some doubts:
so how could I get the current time in server side based on the
current user?
And how could I store DateTime data to show the correct time for
every user?
How can I compare times (example: user.event.created > datetime.now())? What timezone will .now() use?
What TIME_ZONE should I set in settings.py file.
This is for an API, to grab user's timezone via JS is not an option. I get the current user via TokenAuthentication.
Use UTC for settings.py and grab their timezone offset from Javascript:
var utcOffset = -((new Date()).getTimezoneOffset()) / 60;
e.g. for Los Angeles right now utcOffset == -7
Unfortunately this doesn't account for Daylight Savings Time changes later (offset changes to -8), so you may have to figure that out at the time of retrieval in order to get Pacific/Los_Angeles. Otherwise you could always just ask the user in a signup form if it's important for your business.
EDIT: Since you're using an API, you could also try using the IPInfoDB API to geolocate based on client IP address. It's not always completely accurate, but almost always enough to get the correct timezone.
Don't use datetime.now(), use the now() function in the timezone module instead.
from django.utils import timezone
now = timezone.now()
Django will figure out which timezone you are in and compare them accordingly.
user.event.created > timezone.now()
https://docs.djangoproject.com/en/1.8/topics/i18n/timezones/
The solution is to always store unix timestamps in the database. You can generate with time.time() . That means your model should have a Floatfield (or even a BigIntegerField depending on the accuracy needed).
Your template should display the numeric value as it is. Then you need a tiny bit of javascript to convert that unix timestamp to a date time.
new Date(unix_timestamp);
The users of your webapp may be in different time zones, so the conversion to an appropriate time zone is necessary. You can create a middleware and use activate function to set the appropriate time zone. You can get the client-side timezone by doing an ajax api call to Free IP Geolocation API in your landing page and the timezone value can be saved in a cookie variable which can be later accessed in the middleware.
landingpage.html
<script>
$.ajax({
url: 'https://freegeoip.app/json/',
dataType: 'json',
success: function (data) {
document.cookie = 'timezone=' + data['time_zone'] + '; path=/';
}
});
</script>
middleware.py
import pytz
import requests
from django.utils import timezone
class TimezoneMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
tzname = request.COOKIES.get('timezone')
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.deactivate()
return self.get_response(request)
settings.py
MIDDLEWARE = [ ........
'projectname.middleware.TimezoneMiddleware',
]

Django, queryset, filter today

I'm trying to query the database and get the entries for today. So I got a model Events with a date time field. Just to clarify, if I remove the date filter, it does return entries from the database. If I add them it does not. I double-checked that there is an item for today.
views.py
def dashboard(request):
if request.user.is_authenticated():
now = datetime.datetime.now()
events_today = Event.objects.filter(date__year=now.year, date__month=now.month, date__day=now.day)
return render_to_response("dashboard.html", {'today': events_today,}, RequestContext(request))
Update
It does work if I change the USE_TZ to False in settings.py. But it doesn't if it's True.
Update 2
I even uploaded the project to my VPS just in case it had something to do with my computer but still the same.
Instead of datetime.datetime.now() use timezone.now():
from django.utils import timezone
timezone.now()
I think you can try this query:
events_today = Event.objects.filter(date=datetime.datetime.today())

print page generation time

how would I print the time it took to render a page to the bottom of my site in django? i'm not sure of the application flow of django, so I don't know how this would work.
You might be interested in django-debug-toolbar, which includes a request timer and lots of other useful info for debugging things like this.
At the beginning of your view handler, save the current date/time in a variable say time_start and pass that to the template context which renders the page.
Then define a custom template filter that will create timedelta based on datetime.now() value and the original datetime passed in as a parameter like so:
from datetime import datetime
from django import template
register = template.Library()
#register.filter
def get_elapsed(time_start):
return str(datetime.now() - time_start)
Then in your template, simply display:
...
{{ time_start|get_elapsed }}
...

How do I get the visitor's current timezone then convert timezone.now() to string of the local time in Django 1.4?

I understand that the best practice now with Django 1.4 is to store all datetime in UTC and I agree with that. I also understand that all timezone conversation should be done in the template level like this:
{% load tz %}
{% timezone "Europe/Paris" %}
Paris time: {{ value }}
{% endtimezone %}
However, I need to convert the UTC time to the request's local time all in Python. I can't use the template tags since I am returning the string in JSON using Ajax (more specifically Dajaxice).
Currently this is my code ajax.py:
# checked is from the checkbox's this.value (Javascript).
datetime = timezone.now() if checked else None
$ order_pk is sent to the Ajax function.
order = Order.objects.get(pk=order_pk)
order.time = datetime
order.save()
return simplejson.dumps({
'error': False,
'datetime': dateformat.format(datetime, 'F j, Y, P') if checked else 'None'
})
So even if the current time is April 14, 2012, 5:52 p.m. in EST time (my local timezone), the JSON response will return April 14, 2012, 9:52 p.m, because that is the UTC time.
Also I noticed that Django stores a template variable called TIME_ZONE for each request (not actually part of the request variable), so since my is America/New_York, I'm assuming that Django can figure out each visitor's own local timezone (based on HTTP header)?
Anyway, so my question is two-fold:
How do I get the visitor's local timezone in my ajax.py? (Probably pass it as a string argument like {{ TIME_ZONE }})
With the visitor's local timezone, how to convert the UTC timezone.now() to the local timezone and output as a string using Django's dateformat?
EDIT: for #agf
timezone.now() gives the UTC time when USE_TZ = True:
# From django.utils.timezone
def now():
"""
Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.
"""
if settings.USE_TZ:
# timeit shows that datetime.now(tz=utc) is 24% slower
return datetime.utcnow().replace(tzinfo=utc)
else:
return datetime.now()
Is there anyway to convert a datetime to something other than UTC? For example, can I do something like current_time = timezone.now(), then current_time.replace(tzinfo=est) (EST = Eastern Standard Time)?
You need to read the Django Timezones docs carefully.
One important point:
there's no equivalent of the Accept-Language HTTP header that Django could use to determine the user's time zone automatically.
You have to ask the user what their timezone is or just use a default.
You also need to make sure:
USE_TZ = True
in your settings.py.
Once you have a timezone tz, you can:
from django.utils import timezone
timezone.activate(tz)
datetime = timezone.now() if checked else None
to get a timezone-aware datetime object in timezone tz.
While the browser does not send any headers to the server that would indicate a timezone, the JavaScript environment does know its current timezone.
This has two important effects: While the server can't find out your current timezone on the initial request, you can send down some javascript code which will determine the TZ offset and send that information back to the server so that the zone info can be associated with the current session from that point forward.
But more importantly, if you're sending your time value inside JSON data which will be interpreted by the browser client-side, the browser's timezone doesn't need to be known. Instead, you only have to ensure the timezone offset is present in your JSON output so that the browser can do its own timezone math after-the-fact.
var now = new Date()
var offset_minutes = now.getTimezoneOffset() # e.g. 240 for GMT-0400
Since you want the users' timezones, it makes sense to me that this should be done on the browser with Javascript.
I pass something like this into the template:
{"t": str(obj.timestamp))
Where obj is an instance of a django model where the timestamp field is of type DateTimeField.
The template:
<div class="timestring">{{ t }}</div>
...
<script>
$('.timestring').each(function(){
var d = new Date($(this).text());
$(this).text(d.toLocaleDateString() + ", " + d.toLocaleFormat("%r (%Z)"));
})
</script>
For me, this outputs something like: 2/15/2017, 05:22:24 PM (PST)
The relevant documentation:
Javascript Date class (see especially the constructor which accepts datestrings, and the toLocaleFormat() method)
strftime (comes with lots of date formatting shortcuts)

Categories