Django multiple .dates() for query search - django

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.

Related

Django ORM group list of values by date

I'm attempting to perform a group by on a date field, and return values matching that date in a single query. There seem to be many related questions here but they all are aggregating based upon a Count.
Given I have a model like this:
class Book(models.Model):
name = models.CharField(max_length=300)
pubdate = models.DateField()
I would like to run an ORM query which returns distinct name values for pubdate. How can I get a result which looks like
{
'2022-05-04': ['John', 'Sara', 'Bill'],
'2022-05-06': ['Sara', 'Kevin', 'Sally']
...
}

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

In Django, how do I form a queryset that conditionally includes items based on record count in a joined table?

We have a media item table, whose items we want to assign varying date ranges. For example, story X we might like to make available one month, hide it the next month, and make it available again the next month. So we have a date range table where you can specify multiple start/stop dates. But if nothing is specified in this table, we want the item to show up.
Question is, how do I write a query where an item is included in results if it has no entries in the date range table, but if it does have one or more entries, it is only included if today's date falls within that range. Here's what I have so far:
queryset = MediaItem.objects.filter(
is_active=True, publish_date__lt=timezone.now(),
mediaitem_date_range__start_date__lt=timezone.now(),
mediaitem_date_range__stop_date__gt=timezone.now(),
).distinct()
And the date range model is as follows:
class MediaItemDateRange(models.Model):
media_item = models.ForeignKey(MediaItem, related_name='mediaitem_date_range')
start_date = models.DateTimeField(null=True, db_index=True, blank=True)
stop_date = models.DateTimeField(null=True, db_index=True, blank=True)
Currently, this is only yielding results that have entries in the date range table, and most of our items do not have such entries. I only want to exclude an item if it has an entry there and is not in range of that entry's start/stop dates.
Any thoughts?
Okay, looks like I found something that will work. Not sure how efficient the underlying query is doing it this way, but it is Django, so I'll assume the best.
queryset = MediaItem.objects.filter(
is_active=True, publish_date__lt=timezone.now(),
).exclude(
mediaitem_date_range__start_date__gt=timezone.now(),
mediaitem_date_range__stop_date__lt=timezone.now(),
).distinct()
This appears to do what I'm after.

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.

"SELECT...AS..." with related model data in Django

I have an application where users select their own display columns. Each display column has a specified formula. To compute that formula, I need to join few related columns (one-to-one relationship) and compute the value.
The models are like (this is just an example model, actual has more than 100 fields):
class CompanyCode(models.Model):
"""Various Company Codes"""
nse_code = models.CharField(max_length=20)
bse_code = models.CharField(max_length=20)
isin_code = models.CharField(max_length=20)
class Quarter(models.Model):
"""Company Quarterly Result Figures"""
company_code = models.OneToOneField(CompanyCode)
sales_now = models.IntegerField()
sales_previous = models.IntegerField()
I tried doing:
ratios = {'growth':'quarter__sales_now / quarter__sales_previous'}
CompanyCode.objects.extra(select=ratios)
# raises "Unknown column 'quarter__sales_now' in 'field list'"
I also tried using raw query:
query = ','.join(['round((%s),2) AS %s' % (formula, ratio_name)
for ratio_name, formula in ratios.iteritems()])
companies = CompanyCode.objects.raw("""
SELECT `backend_companycode`.`id`, %s
FROM `backend_companycode`
INNER JOIN `backend_quarter` ON ( `backend_companycode`.`id` = `backend_companyquarter`.`company_code_id` )
""", [query])
#This just gives empty result
So please give me a little clue as to how I can use related columns preferably using 'extra' command. Thanks.
By now the Django documentation says that one should use extra as a last resort.
So here is a query without extra():
from django.db.models import F
CompanyCode.objects.annotate(
growth=F('quarter__sales_now') / F('quarter__sales_previous'),
)
Since the calculation is being done on a single Quarter instance, where's the need to do it in the SELECT? You could just define a ratio method/property on the Quarter model:
#property
def quarter(self):
return self.sales_now / self.sales_previous
and call it where necessary
Ok, I found it out. In above using:
CompanyCode.objects.select_related('quarter').extra(select=ratios)
solved the problem.
Basically, to access any related model data through 'extra', we just need to ensure that that model is joined in our query. Using select_related, the query automatically joins the mentioned models.
Thanks :).