I am trying to retrieve data older then 10 days to update that field data. Currently my model is like
class Restaurant(models.Model):
is_approved = models.BooleanField(null=False, default=False)
timestamp = models.DateTimeField(auto_now_add=True)
My database table is
Now when I query the database:
dish = Restaurant.objects.filter(timestamp__gt=datetime.now() - timedelta(days=10))
I get the whole table's data. I even tried to change from a day to 1 day. It still is a full database result.
If you want data that is older then you probably need to use __lt instead of __gt.
import datetime
from django.utils import timezone as tz
d = tz.now() - datetime.timedelta(days=10)
dish = Restaurant.objects.filter(timestamp__lt=d)
Django recomends using timezone.now() instead of datetime.now() to make sure that the timezone info is correct.
This is absolutely just a mistake. Try timestamp__lt for older results. timestamp__gt is recording records for newer results. I asked you to try 1 minute for gt, and it worked. That should display the whole database because all of these are older than 1 min. And also, as said, Django recommends timezone.now() instead of datetime.now(). So you made a error, why timestamp__lt returns the whole database for 10 days is because all posts are less than 10 days old. But lt returns nothing for 1 minute because all of the data is older than 1 minute.
Related
So I have kind of a weird and interesting problem. Lets say I want to be able to group posts on an application like Facebook by months in local time to whoever sent the request. Let's say I have a Post table in Django with the standard created, body and author fields. Where created is the date and time it is created.
Let's say I want to find all posts by a user so that query would look like Post.objects.filter(author=<some name>). I want to be able to send back to the requester for these posts the dates they span. The reason this is slightly tricky is because Django stores in UTC and has no notion of user's time zone unless given.
My initial idea would be make a url that's something like /post/<str:author>/<str:timezone> then somehow convert created date for all queried Post to that time zone and figure out the months. The timezone is needed to cover the edge case that someone posts on the last day of the month. Depending on the time zone that could be the current month in UTC or the next.
How would I find all the months in the requestors timezone that Post span that are by an author?
So for example if someone pings the url: /post/James/PST and let's say James posted 10 times in November and 20 times in October in PST. The response should return ['October', 'November']
I'm currently running on:
Django 3.2.9
Postgresql
Attempted Solutions
>>>qs = Post.objects.annotate(
d=RawSQL("to_char(dt at time zone %s, 'YYYY-MM')", [time_zone]),
).values_list("d", flat=True).distinct()
>>>print(qs.query)
SELECT DISTINCT (to_char(dt at time zone PST, 'YYYY-MM')) AS "d" FROM "cheers_post"
I'd say you'll need to drop down to some Postgres specifics, but this seems to work.
You can see my client timezone is +03:00 (Finland) in the select * and the data saved was in UTC (Z).
akx=# create table x (id serial, dt timestamptz);
CREATE TABLE
akx=# insert into x (dt) values ('2021-06-01T00:00:00Z');
INSERT 0 1
akx=# select * from x;
id | dt
----+------------------------
1 | 2021-06-01 03:00:00+03
(1 row)
akx=# select distinct to_char(dt at time zone 'PST', 'YYYY-MM') from x;
to_char
---------
2021-05
(1 row)
akx=#
Translated to Django, maybe
tz = "PST"
post_dates = Post.objects.annotate(
d=RawSQL("to_char(dt at time zone %s, 'YYYY-MM')", [tz]),
).values_list("d", flat=True).distinct()
or thereabouts?
I need to filter objects older than X number of days. I realize this question exists here: django filter older than day(s)?
However, I not trying to do exactly that, since the number of days, in my case lives inside the model:
class Post(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=500)
createdAt = models.DateTimeField(default=datetime.now, blank=True)
plan = models.ForeignKey(Plan) # This model has the number of days
This is the query I have so far:
EDIT: I changed the days.plan part for the_post.plan.days Meaning that the number of days that I'm using to compare is in each post's plan field.
Post.objects.filter(createdAt__lte=datetime.now() - timedelta(days=the_post.plan.days))
Note the plan.days part of the query. How can I reference the_post.plan.days for this query? Is it possible?
With a small tweak in your Plan model, it is indeed possible to do what you want.
First of all, you'll need to change your Plan days field, which is probably an IntegerField, to DurationField.
Now the catch is that we have to use ExpressionWrapper to achieve the exact same result inside Postgres as the result you'd achieve in Python if you were to get the plan in a separate query.
Finally, your query should be something like:
from django.db.models import F, ExpressionWrapper, DateTimeField
from django.utils import timezone
Post.objects.annotate(target_date=ExpressionWrapper(timezone.now() - F('plan__days'), output_field=DateTimeField())).filter(createdAt__lte=F('target_date'))
Assuming Postgres database:
table_post = Post._meta.db_table
table_plan = Plan._meta.db_table
old_posts = Post.objects.select_related('plan')\
.extra(where=["%s.created_at <= NOW() - INTERVAL '1 day' * %s.days"
% (table_post, table_plan)])
For me you must first grab the plan object.
plan = Plan.objects.filter(...)
and then reference the days
Post.objects.filter(createdAt__lte=datetime.now() - timedelta(days=plan.days))
I'm developing a Django app for logging dives and each dive has a datetime and a timezone in it. I'm using the django-timezone-field app for the timezone.
class Dive(models.Model):
...
date_time_in = models.DateTimeField(default=timezone.now)
timezone = TimeZoneField(default=timezone.get_current_timezone_name())
So the user is able to enter a datetime string ("2016-07-11 14:00") and select a timezone ("Asia/Bangkok" - UTC+0700), I then set the timezone of the datetime to the one given in my view like this:
def log_dive(request):
if request.method == 'POST':
form = DiveForm(request.POST)
if form.is_valid():
dive = form.save(commit=False)
date = dive.date_time_in
date = date.replace(tzinfo=None)
dive.date_time_in = dive.timezone.localize(date)
dive.save()
The database then stores the datetime as UTC in the database (SELECT statement gives it in my local timezone):
# SELECT date_time_in, timezone FROM divelog_dive ORDER BY number DESC;
date_time_in | timezone
------------------------+------------------
2014-07-11 17:00:00+10 | Asia/Bangkok
Now there are two things I'm struggling with:
1) I want to display the dates in the given timezone, however I can't seem to stop it defaulting to the TIME_ZONE setting.
2) If the user edits the record, the time displayed in the edit field should be the one they originally entered (14:00), instead it's showing it in the current timezone (17:00).
Check your timezone setting in settings.py
Do you have USE_TZ = true in your settings file? If you created your app using the djangoadmin-startproject command, it is set by default.
Also, I struggled with timezones at my last job but found that using pytz really helped. Have you tried that package yet?
EDIT: Ok man I may be way off, but since noone else has answered and I feel the timezone struggle, here is something I noticed...
You are replacing the date object with tz_info=None, but wouldn't you want to instead replace that with the timezone from the database? So you would get that timezone and do a replace using the valid format (tzinfo=blah...)?
Like I said I may be way off but if that helps there you go.
Sorry, I don't think I explained my problem very well. I finally figured this out, so I'll answer my own question.
1) turned out to be easy, Django have a template tag for displaying times in a given zone:
{{ dive.date_time_in|timezone:dive.timezone|date:"Y-m-d H:i e" }}
For 2), I came across [1] which lead me to this solution: In the view, after getting the object from the database, I use astimezone(...) to convert the date value (which the DB stores as UTC) into the given timezone. I then use replace(tzinfo=None) to make it naive and then it displays correctly on my form.
def edit_dive(request, dive_id=None):
dive = None
if dive_id != None:
dive = get_object_or_404(Dive, pk=dive_id)
local_date = dive.date_time_in.astimezone(timezone(str(dive.timezone)))
dive.date_time_in = local_date.replace(tzinfo=None)
[1] http://www.saltycrane.com/blog/2009/05/converting-time-zones-datetime-objects-python/
I am noob, so this may be a simple question, but it has me stumped.
I am creating a test form so that each time the user creates a document, the date and time the document was created will be stored in the CreatedDocumentDetails model. I have not yet implemented this code yet, I am focusing on returning the count within the last 24 hours. I have inserted the values into the CreatedDocumentDetails model manually for the time being.
The issue is that I want to make a count of the documents that have been created by the user in the last 24 hours. I can return the total count of the users saved documents, but I am unsure how to write the now date & time field into the if statement to return the count of documents created in the last 24 hours.
I have the following model:
class CreatedDocumentDetails(models.Model):
user = models.ForeignKey(User)
created_document_timestamp = models.DateTimeField(auto_now_add=True, blank=True)
def __unicode__(self):
return unicode(self.user)
Here is the relevant views.py code:
def get_created_documents(user):
created_documents = len(CreatedDocumentDetails.objects.filter(user=user))
return created_documents
I am assuming that I somehow insert the now datetime field into the filter of the get_created_documents view code above.
Firstly, your existing code is very wrong. You should never do len on a queryset that you don't otherwise need to iterate: it fetches all the data, for no reason. Instead, use count():
created_documents = CreatedDocumentDetails.objects.filter(user=user).count()
Secondly, since you already have one condition - on user - it shouldn't be too hard to add another. You just need a date comparison:
date_from = datetime.datetime.now() - datetime.timedelta(days=1)
created_documents = CreatedDocumentDetails.objects.filter(
user=user, created_document_timestamp__gte=date_from).count()
Also you might consider renaming your function and its variables: you're not actually getting the created documents, you're counting them, so count_created_documents or get_created_documents_count would be better names.
I have a model with a datetime field:
class MyModel(models.Model):
created = models.DateTimeField(auto_now = True)
I want to get all the records created today.
I tried:
MyModel.objects.all().filter(created = timezone.now())
and
MyModel.objects.all().filter(created = timezone.now().date())
But always got an empty set. What is the correct way in Django to do this?
EDIT:
It looks strange, but a record, created today (06.04.2012 23:09:44) has date (2012-04-07 04:09:44) in the database. When I'm trying to edit it in the admin panel it looks correct (06.04.2012 23:09:44). Does Django handle it somehow?
Since somewhere in 2015:
YourModel.objects.filter(some_datetime__date=some_date)
i.e. __date after the datetime field.
https://code.djangoproject.com/ticket/9596
There may be a more proper solution, but a quick workup suggests that this would work:
from datetime import timedelta
start_date = timezone.now().date()
end_date = start_date + timedelta( days=1 )
Entry.objects.filter(created__range=(start_date, end_date))
I'm assuming timezone is a datetime-like object.
The important thing is that you're storing an exact time, down to the millisecond, and you're comparing it to something that only has accuracy to the day. Rather than toss the hours, minutes, and seconds, django/python defaults them to 0. So if your record is createed at 2011-4-6T06:34:14am, then it compares 2011-4-6T:06:34:14am to 2011-4-6T00:00:00, not 2011-4-6 (from created date) to 2011-4-6 ( from timezone.now().date() ). Helpful?
Try this
from datetime import datetime
now=datetime.now()
YourModel.objects.filter(datetime_published=datetime(now.year, now.month, now.day))