Getting a query set between a range of dates Django - django

I'm trying to return a list of items in between 2 different dates, a date in the past and the current time using a queryset.
The error I'm getting is TypeError: an integer is required (got type str)
views.py
import datetime
import pytz
first_date = "2020-01-01 19:17:35.909424"
last_date = timezone.now()
I don't want anything returned that has a date in the future
Here is the filter in the query
.filter(hide_sentance_until=(date(first_date), date(last_date)))
This is the full queryset, but it's the above filter causing he issue
zip_flash_sentances = (
model.objects
.filter(show_sentance=True)
.filter(
hide_sentance_until=(date(first_date), date(last_date))
)
.order_by("?")
.filter(username_id = user_id_fk)
.values_list('sentance_eng', 'sentance_esp', 'id')
.first()
)
I thought it might be a comparison problem with dates but here is my model field
models.py
hide_sentance_until = models.DateTimeField(default=datetime.now(), blank=True)
Thanks

You can use gte and lte query attributes:
first_datetime = datetime.datetime.strptime(first_date, '%Y-%m-%d %H:%M:%S.%f')
last_date = timezone.now()
.filter(hide_sentance_until__lte=last_date,hide_sentance_until__gte=first_time)

One thing is that you're specifying a specific value that's determined when your code is compiled to be your default value. To have the actual current date be the value you want:
hide_sentance_until = models.DateTimeField(default=datetime.now, blank=True)
Then you need to parse the datetime out of the string.
date_value = datetime.strptime(first_date, DATETIME_FORMAT_YOU_USE)
Where DATETIME_FORMAT_YOU_USE is the series of format codes from Python that you're using.
Finally you should use the __range queryset field lookup.
.filter(
hide_sentance_until__range=(date_value, timezone.now())
)

Related

Django / PostGreSQL: Create queryset grouped by 'date' when each row has a different timezone

Let's say I have two models:
from django.db import model
class Company(model.Model):
name = models.TextField()
timezone = models.TextField()
class Sale(models.Model):
amount = models.IntegerField()
company = models.ForeignKey('Company')
time = models.DateTimeField()
I want to create a queryset grouped by date and company, where date refers to the calendar date of the sale at the timezone specified on the Company object.
This query:
result = Sale.objects.values(
'company', 'time__date'
).aggregate(
models.Sum('amount')
)
This returns the data in a format that works for me. However, the sales are grouped by UTC day. I want them grouped by the timezone on the Company objects.
What is the cleanest, quickest way to do this?
I know I could dump the entire set of values into Python, like this:
result = Sale.objects.values(
'amount', 'company__timezone', 'time'
).order_by(
'company_timezone'
)
for r in result:
r.date = r.time.astimezone(pytz.timezone(r.company_timezone)).date()
and then groupby, but is there a better way?
The solution is to use the TruncDate function, and pass the timezone string as an argument.
from django.db.models.functions import TruncDate
from django.db.models import F
...
local_time_daily_sales = Sale.objects.annotate(
date=TruncDate(tzinfo=F('company__timezone'))
).values(
date
).annotate(Sum('amount'))

Django - Add Nearest Monday to Queryset

I have an Order model like so:
class Order(models.Model):
created_at = models.DateTimeField(...)
An order can be created at any time, but all orders get shipped out on the following Monday.
How can I add an extra field to my orders queryset called assembly_date that reflects the next Monday (date the order should be shipped)?
I tried creating a custom OrderManager like so, but am not sure how to correctly set the assembly_date:
from django.db.models import F, ExpressionWrapper, DateField
from django.db.models.functions import ExtractWeekDay
class OrderManager(models.Manager):
def get_queryset():
# need help with logic here:
return self.super().get_queryset().annotate(
assembly_date = ExpressionWrapper(
F("created_at") - ExtractWeekDay("created_at"),
output_field = DateField(),
)
)
But this operation results in the following error:
django.db.utils.ProgrammingError: operator does not exist: timestamp with time zone - double precision
LINE 1: ...E NULL END) * 2628000.0) * INTERVAL '1 seconds')) - EXTRACT(...
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
Keep in mind, I want to be able to filter all orders based on their assembly_date.
Basically you need to dynamically generate timedelta inside of annotate. But as far as I know, there is no way you can apply isoweekday() to a datetimefield inside of annotate.
You can have another field as assembly_date in your model, and use it directly to query.
from datetime import timedelta, date
class Order(models.Model):
created_at = models.DateTimeField(...)
assembly_date = models.DateTimeField(...)
def save(self, *args, **kwargs):
weekday = self.created_at.isoweekday() # 1 is Monday, 2 is Tuesday.
daysdiff = 8 - weekday
self.assembly_date = self.created_at + timedelta(days= daysdiff)
super(Order, self).save(*args, **kwargs)

Django filter between two date

My django model datetime field is string. In this case, how to get data between two dates?
models.py
class asdf(models.Model):
recordDate = models.CharField(max_length=20,blank=True)
Change the 'recordDate' to DateField and use the following query:
asdf.objects.filter(recordDate__gte='2019-03-01', recordDate__lte='2019-03-09')
In order to get between range use filter this query:
models.asdf.objects.filter(recordDate__gte='start_date', recordDate__lt='end_date')
start_date and end_date may be string in date formats or datetime parsed object.
This is working for me
remember one thing what you are storing in you db means only date or datetime
when datetime
start = '2021-08-12 21:52:33.118649'
end = '2021-08-13 06:30:46.909572'
user = UserAccount.objects.filter(created_at__gte=start,
created_at__lte=end)
print user
when date
start = '2021-08-12'
end = '2021-08-13'
user = UserAccount.objects.filter(created_at__gte=start,
created_at__lte=end)
print user
or you can filter by using __range here also
start = '2021-08-12 21:52:33.118649'
end = '2021-08-13 06:30:46.909572'
user = UserAccount.objects.filter(created_at__range=(start, end))
print user
if you you are storing in db datatime and you want to retrieve only date from db
from datetime import datetime
datetime.strptime('2014-12-04', '%Y-%m-%d').date()

Django: Combine a date and time field and filter

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

Django Date formatting in forms query

Hi I have a model containing:
class MyModel(models.Model):
id = models.IntegerField(primary_key=True)
recorded_on = models.DateField()
precipitation = models.FloatField(null=True, blank=True)
I have a form which looks like this:
class QueryForm(forms.Form):
precipitation = forms.BooleanField(label=ugettext_lazy('Precipitation'),)
startdate = forms.DateField(widget = widgets.AdminDateWidget, label=ugettext_lazy('Start Date'),)
enddate = forms.DateField(widget = widgets.AdminDateWidget, label=ugettext_lazy('End Date'),)
In my views.py I have one view for the form and a separate view for collecting the data via GET. This is very simplified version of the second view.py:
def results(request):
if 'q' in request.GET:
...
startdate = request.GET.get('startdate', None)
enddate = request.GET.get('enddate', None)
data = MyModel.objects.filter(recorded_on__range = (startdate, enddate))
...
My date variables in GET are of the format 'YYYY-MM-DD'.
The problem is that the query raises this error:
coercing to Unicode: need string or buffer, datetime.date found
What is the best way to deal with my date format to make the query?
You'll need to create Date objects from your form data, which is currently a string. The error you're getting is from django trying to compare those strings to the dates on the models.
so:
from datetime import datetime
format = '%d-%m-%Y' # Or whatever your date format is
st = datetime.strptime(startdate, format)
ed = datetime.strptime(enddate, format)
data = MyModel.objects.filter(recorded_on__range=(st.date(), ed.date()))
Should point you in the right direction.
I am a bit confused about the error message (i.e. where does the error occur - when you make the query?).
However, I used this to convert a string from a url parameter to a datetime.date:
def things_by_appointment(request, appointment_date):
'''
Things with appointment date yyyy-mm-dd
'''
try:
as_date = datetime.datetime.strptime( appointment_date, '%Y-%m-%d').date
except ValueError:
return HttpResponseBadRequest('%s is not a correct date' % appointment_date )
things = Thing.objects.filter(
Q( appointment_date = as_date ),
#...
Althoug the string is from the path and not from the query string, it should not make a difference.