Django QuerySet equivalent for SQL's between and - django

Let's say I have the following table:
Employee
name start_date end_date
John 2009-10-10 2009-12-31
Joe 2009-12-01 2010-05-10
I also have a curr_date = '2009-11-01'. If I want to get all employees where curr_date should be between an employee's start_date and end_date inclusive, the corresponding SQL is:
SELECT *
FROM employee
WHERE curr_date between start_date and end_date
The corresponding Django QuerySet I came up with is:
Employee.objects.filter(start_date__lte=curr_date, end_date__gte=curr_date)
Is there an alternate way to do the above with Django's QuerySet, the __range method doesn't quite work for the above case.

You're right, the __range method won't work, so no, there is no way to use the Django ORM to create the SQL you are after.
Is there a problem with using the .filter method which you came up with?

Related

Filter queryset by year between two date fields

I have a start_date and an end_date fields in my model. The user shall be able to filter records by selecting a year value, so that records that span over multiple years should be shown if the year selected is included.
For example:
Selected year: 2019
start_date
end_date
2017-03-12
2021-09-03
2019-12-12
2020-06-05
I can do this query by raw SQL like that:
SELECT * FROM `orders` WHERE '2019' BETWEEN YEAR(`start_date`) AND YEAR(`end_date`);
How can I do this using Django ORM and avoid raw SQL queries? Because I am already using the ORM in multiple filters and only remaining this bit.
Try this:
YourModel.objects.filter(
start_date__year__lte=2019,
end_date__year__gte=2019,
)

Django multiple .dates() for query search

I have a module that looks something like
class Entry(models.Model):
user = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(default=datetime.datetime.now())
#
# date for the post
date = models.DateField()
date stores the date for the post will show. What I want to get is a listing of all months and years for all posts by a user. So it will look something like
7/2015
8/2015
10/2015
I've tried this
Entry.objects.filter(user=self.user) \
.order_by('-date') \
.dates('date', 'year') \
.distinct()
That gives me the unique years.. Is there anyway to do this in a query where I dont have to select the unique months and iterate over them to create an object.
My raw sql looked like
SELECT DISTINCT YEAR(date) AS y, MONTH(date) AS m FROM entries WHERE userid ='". $this->id ."' ORDER BY date DESC
If I understand your question correctly I think you just need to use month as the second parameter to the QuerySet.dates function. E.g.,
self.user.entry_set.order_by('-date').dates('date', 'month')
would return a list of distinct year/month values for all of self.user's Entry.
You can then format each datetime object as you see fit.

Count number of distinct records by date in Django

following this question:
Count number of records by date in Django
class Review(models.Model):
venue = models.ForeignKey(Venue, db_index=True)
review = models.TextField()
datetime_visited = models.DateTimeField(default=datetime.now)
It is true that the following line solves the problem of count number of records by date:
Review.objects.filter
.extra({'date_visited' : "date(datetime_visisted)"})
.values('date_visited')
.annotate(visited_count=Count('id'))
However, say I would like to have a distinct count, that is, I would like to avoid Review objects from the same id on the same day, what can I do?
I tried:
Review.objects.filter.
.extra({'date_visited': "date(datetime_visited)"})
.values('date_visited', 'id')
.distinct()
.annotate(Count('id'))
but it seems not working
Your problem is that you're including id in your values(), which is making all records unique, defeating distinct(). Try this instead:
Review.objects.filter.
.extra({'date_visited': "date(datetime_visited)"})
.values('date_visited')
.distinct()
.annotate(Count('date_visited'))

Django Queryset - extracting only date from datetime field in query (inside .value() )

I want to extract some particular columns from django query
models.py
class table
id = models.IntegerField(primaryKey= True)
date = models.DatetimeField()
address = models.CharField(max_length=50)
city = models.CharField(max_length=20)
cityid = models.IntegerField(20)
This is what I am currently using for my query
obj = table.objects.filter(date__range(start,end)).values('id','date','address','city','date').annotate(count= Count('cityid')).order_by('date','-count')
I am hoping to have a SQL query that is similar to this
select DATE(date), id,address,city, COUNT(cityid) as count from table where date between "start" and "end" group by DATE(date), address,id, city order by DATE(date) ASC,count DESC;
At least in Django 1.10.5, you can use something like this, without extra and RawSQL:
from django.db.models.functions import Cast
from django.db.models.fields import DateField
table.objects.annotate(date_only=Cast('date', DateField()))
And for filtering, you can use date lookup (https://docs.djangoproject.com/en/1.11/ref/models/querysets/#date):
table.objects.filter(date__date__range=(start, end))
For the below case.
select DATE(date), id,address,city, COUNT(cityid) as count from table where date between "start" and "end" group by DATE(date), address,id, city order by DATE(date) ASC,count DESC;
You can use extra where you can implement DB functions.
Table.objects.filter(date__range(start,end)).extra(select={'date':'DATE(date)','count':'COUNT(cityid)'}).values('date','id','address_city').order_by('date')
Hope it will help you.
Thanks.

Django date effective retrieval of ORM records

If I have a Django Employee model with a start_date and end_date date field, how can I use get in the ORM to date effectively select the correct record if different versions of the record exist over time based on these date fields?
So I could have the following records:
start_date, end_date, emp
01/01/2013, 31/01/2013, Emp1
01/02/2013, 28/02/2013, Employee1
01/03/2013, 31/12/4000. EmpOne
And if today's date is 10/02/2013 then I would want Employee1.
Something similar to:
from django.utils import timezone
current_year = timezone.now().year
Employee.objects.get(end_date__year=current_year)
or
res = Employee.objects.filter(end_date__gt=datetime.now()).order_by('-start_date')
Or is there a more efficient way of doing the same?
Your second example looks fine. I corrected the filter parameters to match your start_date constraints. Also, i added a LIMIT 1 ([:1]) for better performance:
now = datetime.now()
employees = Employee.objects.filter(start_date__lt=now, end_date__gt=now).order_by('-start_date')
employee = employees[:1][0] if employees else None