I want to send an email to users who haven't activated their accounts every 120 days. I'm using a DateTimeField for their created attribute.
How can I retrieve a queryset of users for whom created % 120 == 0?
Here's what I'm trying, using annotate and F objects:
members = Member.objects.annotate(
days_old=(datetime.datetime.now() - F('created'))
)
members = members.annotate(modulo_days=F('days_old') % 120)
members = members.filter(modulo_days=0)
...but this returns the errors:
TypeError: expected string or buffer
ProgrammingError: operator does not exist: interval % integer
How can I retrieve this queryset looking for the modulo of a timestamp on a Django model?
Another way of doing a queryset that could work for you:
from datetime import timedelta
from datetime import datetime
to_compare_datetime = datetime.now() - timedelta(days=180)
members = Member.objects.filter(account_activated=False, created__year=to_compare_datetime.year, created__month=to_compare_datetime.month, created__day=to_compare_datetime.day)
I'm supposing that your Member model has a field account_activated, and that the created field is a DateTimeField. Hope this can help you :)
Related
I am writing queryset that will return this type
date
total_shipping_fee
2021-04-16
5,000
2021-04-17
100,000
where
class Payments(models.Model):
created = models.DateTimeField()
.....
SELECT DATE(created) from payment_payment .... group by 'created' -> outputs a correct query
My question is how to query/ or cast
Payment.objects.filter(created_range=("2021-05-14", "2021-05-14")).values('created').annotate(total_shipping_fee=Sum('total_shipping_fee'))
so that I can have queryset in above raw sql. I think that is my problem to CAST DATE(created) in django queryset. Thanks
You can work with:
from django.db.models import F, Sum
Payment.objects.filter(
created__date_range=('2021-05-14', '2021-05-14')
).values(create_date=F('created__date')).annotate(
total_shipping_fee=Sum('total_shipping_fee')
).order_by('create_date')
here we thus first takes as values the truncated date of the DateTimeField, and then we use .order_by(…) [Django-doc] to enforce grouping by that date.
The output is a QuerySet of dictionaries, each with two items: { 'create_date': …, 'total_shipping_fee': … }.
I am pretty new to django and haven't been able to find a way to get the elapsed time between two DateTimeFields and save it to another model.
from django.db import models
class Timesheet(models.Model):
startTime = models.DateTimeField(auto_now_add=True)
endTime = models.DateTimeField(blank=True, null=True)
duration = models.DateTimeField(endTime - startTime)
def _str_(self):
return self.startTime
How can I make duration = endTime - startTime?
I am also using a PostgreSQL database.
I wouldn't use a dedicated model field for the duration.
I would use a property on the model instead for the same functionality.
Something like:
#property
def duration(self)
return self.end_time - self.startime
Lucas has a good idea of using an annotation, but if you have a Timesheet instance somewhere that didn't come from that object manager and was not previously annotated, you would have to do a separate database hit to actually annotate it.
This property is used as such:
some_timesheet_instance.duration
Use annotate() to compute the duration field at query time for each object in the queryset
from django.db.models import F, ExpressionWrapper, fields
timesheets = Timesheet.objects.annotate(
duration=ExpressionWrapper(
F('endTime') - F('startTime'),
output_field=fields.DurationField()
)
)
timesheets[0].duration # datetime.timedelta(0, 722, 18373)
Is possible perform another queryset methods over annotations like filter(), order_by(), aggregate(), etc.
timesheets.order_by('-duration')
timesheets.aggregate(Avg('duration')) # {'duration__avg': datetime.timedelta(0, 26473, 292625)}
duration = timesheet.end_time - timesheet.start_time
When you substract two datetime instances you don't get another datetime instance but a timedelta instace, which is just the days, seconds and microseconds difference between the two datetimes. You can't store a timedelta in a DateTimefield, but you can use an IntegerField, for example:
days_in_seconds = duration.days * 86400 # days difference by seconds in a day
duration_in_seconds = duration.seconds + days_in_seconds # duration in seconds
When you want to access the duration as timedelta you just do:
import datetime
duration = datetime.timedelta(seconds=timesheet.duration)
You can also store it as FloatField as suggested in this question.
I need to query a model by their local time.
send_reminder_query = PersonModel.objects.filter('Is after 7pm thier localtime')
The person will have a zipcode field and I have a function to get the timezone by their zipcode. I'd also be willing to write a migration script to populate the timezone on the Person model but I still don't see how to make the query.
send_reminder_query = PersonModel.objects.filter(tzinfo='...', ?)
I was able to solve the problem by pre processing the data to store the person's timezone. Then using pytz I do this.
from django.utils import timezone
import pytz
valid_timezones = []
for tz in list_of_timezones:
local_time = now().astimezone(pytz.timezone(tz))
if 19 < local_time.hour < 20:
valid_timezones.append(tz)
reminders = Person.objects.filter(timezone__in=valid_timezones)
I have a django model that has a date field and a separate time field. I am trying to use a filter to find a value on the latest record by date/time that is less than the current record's date time.
How do I use annotate/aggregate to combine the date and time fields into one and then do a filter on it?
models.py
class Note(models.model):
note_date = models.DateField(null=True)
note_time = models.TimeField(null=True)
note_value = models.PositiveIntegerField(null=True)
def get_last(n):
"""
n: Note
return: Return the note_value of the most recent Note prior to given Note.
"""
latest = Note.objects.filter(
note_date__lte=n.note_date
).order_by(
'-note_date', '-note_time'
).first()
return latest.note_value if latest else return 0
This will return any notes from a previous date, but if I have a two notes on the same date, one at 3pm and one at 1pm, and I send the 3pm note to the function, I want to get the value of the 1pm note. Is there a way to annotate the two fields into one for comparison, or do I have to perform a raw SQL query? Is there a way to convert the date and time component into one, similar to how you could use Concat for strings?
Note.objects.annotate(
my_dt=Concat('note_date', 'note_time')
).filter(
my_dt__lt=Concat(models.F('note_date'), models.F('note_time')
).first()
I am too late but here is what I did
from django.db.models import DateTimeField, ExpressionWrapper, F
notes = Note.objects.annotate(my_dt=ExpressionWrapper(F('note_date') + F('note_time'), output_field=DateTimeField()))
Now we have added a new field my_dt of datetime type and can add a filter further to do operations
Found an answer using models.Q here: filter combined date and time in django
Note.objects.filter(
models.Q(note_date__lt=n.note_date) | models.Q(
note_date=n.note_date,
note_time__lt=n.note_time
)
).first()
I guess I just wasn't searching by the right criteria.
Here is another Approach which is more authentic
from django.db.models import Value, DateTimeField
from django.db.models.functions import Cast, Concat
notes = Note.objects.annotate(my_dt=Cast(
Concat('note_date', Value(" "), 'note_time', output_field=DateTimeField()),
output_field=DateTimeField()
).filter(my_dt__lte=datetime.now())
Here is another solution following others.
def get_queryset(self):
from django.db import models
datetime_wrapper = models.ExpressionWrapper(models.F('note_date') + models.F('note_time'), output_field=models.DateTimeField())
return Note.objects.annotate(
note_datetime=datetime_wrapper
).filter(note_datetime__gt=timezone.now()).order_by('note_datetime')
In my model I want to be able to input duration, like 2 years, 5 months, etc.
In version 1.8 DurationField was introduced so I tried using that:
In my model I have
user_validPeriod = models.DurationField()
Trying to add a new User from my admin panel, If I try typing something like 2d or 2 days in the appearing text-field though I get Enter a valid duration.
Can someone provide me with an example of how this field is supposed to be used?
To use a DurationField in django 1.8 you have to use a python datetime.timedelta instance like this:
Considering this model :
from django.db import models
class MyModel(models.Model):
duration = models.DurationField()
You can set a duration this way :
import datetime
my_model = MyModel()
my_model.duration = datetime.timedelta(days=20, hours=10)
And query it this way :
# Equal
durations = MyModel.objects.filter(duration=datetime.timedelta(*args, **kwargs))
# Greater than or equal
durations = MyModel.objects.filter(duration__gte=datetime.timedelta(*args, **kwargs))
# Less than or equal
durations = MyModel.objects.filter(duration__lte=datetime.timedelta(*args, **kwargs))
More info on datetime.timedelta here and on DurationField here.
In your admin panel, you can enter a duration with a string with following format : [DD] [[hh:]mm:]ss