Reputation: 1006
My model has a date field and i want to filter the model by the last 7 days.
class Count(models.Model):
task = models.ForeignKey(Task, related_name = 'counts', on_delete = models.CASCADE)
start_time = models.DateTimeField(null = True, blank = True)
end_time = models.DateTimeField(null = True, blank = True)
time_spent = models.PositiveIntegerField()
deleted = models.BooleanField(default = False)
class Meta():
ordering = ['accesses']
def __str__(self):
return f'{self.task.department} - {self.accesses.first().user} [{self.time_spent} min]'
def stamped_date(self):
if not self.start_time:
return self.accesses.first().date
return self.start_time
def users(self):
return list(set(map(lambda x: x.user, list(self.accesses.all()))))
I need to filter every count that has "stamped_date" in the last 7 days.
What i tried to do (in the model):
def daysBy(self):
return (datetime.now() - self.stamped_date()).days
to filter like this:
Count.objects.filter(daysBy__let = 7)
However, datetime.now() requires a timezone object, otherwise will throw the follwing error:
TypeError: can't subtract offset-naive and offset-aware datetimes
I'm also feeling this might not be the most correct way of achieving my goal, please correct me with a better way.
Or.. give me a way of inserting a timezone object related to the TIME_ZONE setting.
Upvotes: 0
Views: 68
Reputation: 94
You want to filter the queryset and get a count if stamped_date is within seven days
You'll do yourself justice if this is a standard requirement to build a model manager to handle this
What you're aiming for. Because by doing this you can call count() on your returned queryset.
import datetime
Count.objects.get_stamped_date().count()
Model Manager would be like so,
class CountManager(models.Manager):
def get_stamped_date(self):
todays_date = timezone.now()
seven_days_ago = datetime.timedelta(days=7)
qs = super().get_queryset()
count = qs.filter(start_time__range=[seven_days_ago, todays_date])
return count
Then update your model to include the manager
Count(models.Models):
objects = CountManager()
To be honest, your stamped_date should be a field attribute which should work with your save() method of your model so its a little confusing why you did it the way you did. Under the save method (standard) let the model instance check every time there isn't a start time and save your self.access datetime field which I dont see reference to here to the stamped_date field
Also just for a cherry on the top, would perhaps be even better to allow an argument to the model manager to say how many days so its not fixed to seven days.
Upvotes: 3
Reputation: 670
You could achieve this query using the range operator like this.
oldDate = datetime.now() - datetime.timedelta(days =7)
Count.objects.filter(start_time__range=(oldDate, datetime.now()))
EDIT : to achieve this kind of querying with the filter method, your method generated value should be a model field. You can achieve this by overriding the save method like this :
# Create the stamped date model field
stamped_date = models.DateTimeField(null=True)
#override the save method for your custom saving logic
def save(self, *args, **kwargs):
if not self.start_time:
self.stamped_date = self.accesses.first().date
else:
self.stamped_date = self.start_time
super().save(*args, **kwargs) # Call the "real" save() method.
Upvotes: 1
Reputation: 80
from Time Zones - Django Documentation:
When time zone support is enabled (USE_TZ=True), Django uses time-zone-aware datetime objects. If your code creates datetime objects, they should be aware too. In this mode, the example above becomes:
from django.utils import timezone now = timezone.now()
I hope this helps.
Upvotes: 2