I have this MySQL specific query
SELECT SUM(trip_amount) as tp , DATE(FROM_UNIXTIME(request_time)) as timestamp
FROM trip_master
WHERE trip_master.date > 1493836200
AND trip_master.date < 1493922600
AND trip_master.id = 6
GROUP BY timestamp
Implemented this query in Django,
Trip.objects.filter(id=userid,date__gt = start,date__lt = end).annotate(trip_amount = Sum('trip_amount')).extra({'timestamp':'DATE(FROM_UNIXTIME(request_time))'})
As defined I have to convert time stamp to date to have grouping from dates. Has reached at the almost level but not getting group by dates.
Any help is much appreciated
Try:
from django.db.models.expressions import RawSQL
Trip.objects.filter(
id=userid,
date__gt=start,
date__lt=end
).annotate(
timestamp=RawSQL('DATE(FROM_UNIXTIME(request_time))', [])
).values(
'timestamp'
).annotate(
trip_amount=Sum('trip_amount')
)
See Group objects by dates
I have my django app and I want to pass from url to view years in format, for example: 2017-18.
Below I got an error that my date have to be in date format - YYYY-MM-DD.
Here is my url:
url(r'^(?P<branch_slug>/production/(?P<year1>[0-9]{4})-(?P<year2>[0-9]{2})$', Events.as_view()),
Here is my view:
def get_queryset(self):
season = Events.objects.get(start=self.kwargs['year1'], end=self.kwargs['year2'])
filter_['start__gte'] = season.start
filter_['start__lte'] = season.end
return self.model.objects.filter(**filter_)
The start and end attributes of your Event object are probably datetime.date instances (if you are using a DateField). So you need to convert the year1 and year2 variables from your url to a date before using them in your view.
some_date = datetime.date(YYYY, 1, 1)
Your original question, and others' answers here, match a season that begins on 1 January of year1 and ends on 31 December of year2. I suspect that this is not what you want, and that instead you want a season which starts sometime in year1 and ends some time in year2, and then you want to look up events between those dates.
Django has a special lookup for matching only the year part of a date, using __year=. See https://docs.djangoproject.com/en/1.10/ref/models/querysets/#year for more on this. You don't need to convert the input values to dates to use this; it works with integers.
def get_queryset(self):
# Get a season starting any time in year1 and ending in year2
season = Events.objects.get(
start__year=int(self.kwargs['year1']),
end__year=int(self.kwargs['year2']),
)
As with others have commented you should change the URL regex to match 4-digit years to avoid ambiguity.
url(r'^(?P<branch_slug>/production/(?P<year1>[0-9]{4})-(?P<year2>[0-9]{4})$', Events.as_view()),
As #dentemm pointed out, to do filtering on datetime fields, strings representing date must be converted to datetime objects. My suggestion is to use datetime field. Pass year string as you are already doing and then in the views convert date string to a datetime object to do filtering
import datetime
def get_queryset(self):
start=datetime.strptime('1-1-'+self.kwargs['year1'], '%m-%d-%Y')
end=datetime.strptime('12-31-'+self.kwargs['year2'], '%m-%d-%Y')
season = Events.objects.get(start=start, end=end)
filter_['start__gte'] = season.start
filter_['start__lte'] = season.end
return self.model.objects.filter(**filter_)
datetime.strptime('1-1-'+self.kwargs['year1'], '%m-%d-%Y') will create datetime object for start date with date as 1st of january for given start date string and datetime.strptime('12-31-'+self.kwargs['year2'], '%m-%d-%Y') will create datetime object for end date with date as 31st of december for given end date string. To make sure all objects created within end date is returned by query you may do something like
`end_date = datetime.strptime('31-12-'+self.kwargs['year1']+'T23:59:59.999999', '%m-%d-%YT%H:%M:%S.%f')`
As #Alasdair mnetioned in one of the comments change (?P<year2>[0-9]{2}) to (?P<year2>[0-9]{4}) to accept 4 digit year string from url
If you have a datetime/date field in your model, use the year lookup from Django:
https://docs.djangoproject.com/en/1.10/ref/models/querysets/#year
As it says:
Entry.objects.filter(pub_date__year=2005)
is equal in sql to:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
I take a timestamp for my Institution class:
class Institution(models.Model):
timestamp_utc = models.DateTimeField()
If there is an entry in the DB that has the same year, month and date (not time), then I want to update the value of the entry. If not, then I want to create a new entry.
The conditional is as follows:
if Institution.objects.filter(timestamp_utc.strftime("%Y/%m/%d")=b['timestamp_utc'].strftime("%Y/%m/%d")).exists():
I am getting this error:
Exception Value: keyword can't be an expression
Is there a way to filter the DB object with a manipulated keyword?
You can just filter by the date range, i.e. time stamps that are great than or equal to the date, and less that the date + 1 day.
from datetime import relativedelta
date_start = b['timestamp_utc'].strftime("%Y-%m-%d")
date_end = (b['timestamp_utc'] + relativedelta(days=1)).strftime("%Y-%m-%d")
if Institution.objects.filter(
timestamp_utc__gte=date_start, timestamp_utc__lt=date_end
).exists():
I want to display and save date data as one of the following forms:
year-month-day
year-month
year
To achieve this, I have the following model structure:
I have a Model with following structure
CHOICES = [
(0, "Year/Month/Date"),
(1, "Year/Month"),
(2, "Year"),
]
class MyModel(Model):
my_date = Models.DateField(...)
my_date_format = Models.SmallIntegerField(choices=CHOICES)
And in the ModelForm
class MyForm(ModelForm):
class Meta:
model = MyModel
widgets = {"my_date": SelectDateWidget(required=False), }
My logic is as follows:
If user sets day, month and year; then save the date as is and set my_date_format to 0.
If user sets month and year (leave day blank); then I will set day to 1 and set my_date_format to 1, so I will ignore day part of my_date data afterwards.
If user sets year (leave day and month blank ); then I set day and month to 1 and set my_date_format to 2, so I will ignore day and month part of my_date data afterwards.
My problem is with form validation. SelectDateWidget needs to validate date and coerce it to python datetime.date but I need the data as it was posted to check which field is blank to set my_date_format value.
I have to save date data as date to my database so I can query it correctly.
How should I override form.clean() method?
I would try something like that.
Disclaimer: not tested but maybe it can provides ideas to you.
def clean(self):
cleaned_data = super(MyForm, self).clean()
# Check the my_date_format value here
...
# Then generate appropriate datetime according your own rules
my_datetime = ...
# Add datetime to the cleaned_data dictionnary
cleaned_data['my_date'] = my_datetime
return cleaned_data
how do i get queryset of people with a birthday in the next X days? I saw this answer, but it does not suit me, because gets people only with current year of birth.
Assuming a model like this--
class Person(models.Model):
name = models.CharField(max_length=40)
birthday = models.DateTimeField() # their next birthday
The next step would be to create a query filtering out any records with birthdays having a month and day in between (now.month, now.day) and (then.month, then.day). You can actually access the month and day attributes of the datetime object using the queryset API by passing Person.objects.filter a keyword argument like this: "birthday__month." I tried this with an actual queryset API method like "birthday__month__gte" and it failed though. So I would suggest simply generating a literal list of month/day tuples representing each (month, day) in the date range you want records for, then compose them all into a query with django.db.models.Q, like so:
from datetime import datetime, timedelta
import operator
from django.db.models import Q
def birthdays_within(days):
now = datetime.now()
then = now + timedelta(days)
# Build the list of month/day tuples.
monthdays = [(now.month, now.day)]
while now <= then:
monthdays.append((now.month, now.day))
now += timedelta(days=1)
# Tranform each into queryset keyword args.
monthdays = (dict(zip(("birthday__month", "birthday__day"), t))
for t in monthdays)
# Compose the djano.db.models.Q objects together for a single query.
query = reduce(operator.or_, (Q(**d) for d in monthdays))
# Run the query.
return Person.objects.filter(query)
After debugging, this should return a queryset with each person who has a birthday with month and day equal to any of the months or days in the specified list of tuples.
Assuming it's datetime field do something like this (using future_date from dimosaur answer):
Profile.objects.get(
Q(birthday__lte=future_date),
Q(birthday__gte=datetime.date.today())
)
I can think of 2 ways without using custom queries, both with "problems"
1) Not efficient as it does 1 query per day
start = datetime.date.today()
max_days = 14
days = [ start + datetime.timedelta(days=i) for i in xrange(0, max_days) ]
birthdays = []
for d in days:
for p in Profile.objects.filter(birthday__month=d.month, birthday__day=d.day):
birthdays.append(p)
print birthdays
2) Single query, but requires a model change. You would need to add bday_month and bday_day integer fields. These can obviously be populated automatically from the real date.
The limitation of this example is that you can only check against 2 months, start month and the end month. Setting 29 days you could jump over february, showing only Jan 31 and Mar 1.
from django.db.models import Q
start = datetime.date.today()
end = start + datetime.timedelta(days=14)
print Profile.objects.filter(
Q(bday_month=start.month) & Q(bday_day__gte=start.day) |
Q(bday_month=end.month) & Q(bday_day__lte=end.day)
)
If X is a constant that you know:
import datetime
future_date = datetime.date.today() + datetime.timedelta(days=X)
Profile.objects.filter(
birth_date__month=future_date.month,
birth_date__day=future_date.day
)
Something like that.
I have tried to do it in a really silly way, but seems it works:
import datetime
from django.db.models import Q
x = 5
q_args = ''
for d in range(x):
future_date = datetime.date.today() + datetime.timedelta(days=d)
q_args += 'Q(birth_date__month=%d, birth_date__day=%d)%s' % (
future_date.month,
future_date.day,
' | ' if d < x - 1 else ''
)
people = People.objects.filter(eval(q_args))
I was unsatisfied with all replies here. They are all a variant on "check one date/year by one in a range...", making a long, ugly queries. Here is a simple solution, if one is willing to denormalize a bit:
Change your model so instead of just datetime birthdate(yyyy, mm, dd) holding the real date you add a datetime birthday(DUMMY_YEAR, mm, dd) column. So every person in your DB will have saved its real birth date, and then a another birth date with a fixed year, shared with everyone else. Don't show this second field to users, though, and don't allow them to edit it.
Once you edited your model, make sure the birthdate and birthday are always connected by extending models.Model save method in your class:
def save(self, *args, **kwargs):
self.birthday = datetime.date(BIRTHDAY_YEAR,
self.birthdate.month, self.birthdate.day)
super(YOUR_CLASS, self).save(*args, **kwargs)
And once you ensured that whenever a date is saved as birthdate, the birthday is updated too, you can filter it with just birthday__gte/birthday__lte. See an excerpt from my admin filter, where I take care of a year boundary:
def queryset(self, request, queryset):
if self.value() == 'today':
# if we are looking for just today, it is simple
return queryset.filter(birthday = datetime.date(
BIRTHDAY_YEAR, now().month, now().day
))
if self.value() == 'week':
# However, if we are looking for next few days,
# we have to bear in mind what happens on the eve
# of a new year. So if the interval we are looking at
# is going over the new year, break the search into
# two with an OR.
future_date = (now() + datetime.timedelta(days=7)).date()
if (now().year == future_date.year):
return queryset.filter(
Q(birthday__gte = datetime.date(
BIRTHDAY_YEAR, now().month, now().day
)) &
Q(birthday__lte = datetime.date(
BIRTHDAY_YEAR,
future_date.month,
future_date.day)
)
)
else:
return queryset.filter(
# end of the old year
Q(birthday__gte = datetime.date(
BIRTHDAY_YEAR, now().month, now().day
)) &
Q(birthday__lte = datetime.date(BIRTHDAY_YEAR,12, 31)) |
# beginning of the new year
Q(birthday__gte = datetime.date(BIRTHDAY_YEAR, 1, 1)) &
Q(birthday__lte = datetime.date(BIRTHDAY_YEAR,
future_date.month,
future_date.day)
)
)
In case you wonder what the Q() is, look on Complex lookups with Q objects