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']
...
}
Related
how I get get only one column of my model using filter
ids = model1.objects.filter(key=value)
return model2.objects.filter(column__in=ids)
in above example first filter should return list of ids of model1
and in second example data will be return using in of 1st result ids
NOTE: model1 it's having number of field and one is id
You can select only some columns using values_list or values:
ids = Model1.objects.filter(key=value).values_list('id', flat=True)
However, if you are going to filter on that, then this query is redundant at all (if I properly understand your schema).
Consider the following two models:
class Model1(models.Model):
name = models.CharField(max_length=50)
class Model2(models.Model):
m1_ref = models.ForeignKey(Model1, models.CASCADE)
Then two following queries are equivalent (but first is slower):
ids = Model1.objects.filter(name=value).values_list('pk', flat=True)
result = Model2.objects.filter(m1_ref__in=ids)
and
result = Model2.objects.filter(m1_ref__name=value)
I'm trying to get all values in current table, and also get some fields in related tables.
class school(models.Model):
school_name = models.CharField(max_length=256)
school_type = models.CharField(max_length=128)
school_address = models.CharField(max_length=256)
class hometown(models.Model):
hometown_name = models.CharField(max_length=32)
class person(models.Model):
person_name = models.CharField(max_length=128)
person_id = models.CharField(max_length=128)
person_school = models.ForeignKey(school, on_delete=models.CASCADE)
person_ht = models.ForeignKey(hometown, on_delete=models.CASCADE)
how to quick select all info i needed into a dict for rendering.
there will be many records in person, i got school_id input, and want to get all person in this school, and also want these person's hometown_name shown.
i tried like this, can get the info i wanted. And any other quick way to do it?
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name'))
person_name, person_id, school_name, school_address, hometown_name
if the person have many fields, it will be a hard work for list all values.
what i mean, is there any queryset can join related tables' fields together, which no need to list fields in values.
Maybe like this:
m=person.objects.filter(person_school_id=1).XXXX.values()
it can show all values in school, and all values in hometown together with person's values in m, and i can
for x in m:
print(x.school_name, x.hometown_name, x.person_name)
You add a prefetch_related query on top of your queryset.
prefetch_data = Prefetch('person_set, hometown_set, school_set', queryset=m)
Where prefetch_data will prepare your DB to fetch related tables and m is your original filtered query (so add this below your Person.objects.filter(... )
Then you do the actual query to the DB:
query = query.prefetch_related(prefetch_data)
Where query will be the actual resulting query with a list of Person objects (so add that line below the prefetch_data one).
Example:
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name'))
prefetch_data = Prefetch('person_set, hometown_set, school_set', queryset=m)
query = query.prefetch_related(prefetch_data)
In that example I've broken down the queries into more manageable pieces, but you can do the whole thing in one big line too (less manageable to read though):
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name')).prefetch_related('person, hometown, school')
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.
class Book(models.Model):
name = models.CharField(max_length=127, blank=False)
class Author(models.Model):
name = models.CharField(max_length=127, blank=False)
books = models.ManyToMany(Books)
I am trying to filter the authors so I can return a result set of authors like:
[{id: 1, name: 'Grisham', books : [{name: 'The Client'},{name: 'The Street Lawyer}], ..]
Before I had the m2m relationship on author I was able to query for any number of author records and get all of the values I needed using the values method with only one db query.
But it looks like
Author.objects.all().values('name', 'books')
would return something like:
[{id: 1, name: 'Grisham', books :{name: 'The Client'}},{id: 1, name: 'Grisham', books :{name: 'The Street Lawyer'}}]
Looking at the docs it doesn't look like that is possible with the values method.
https://docs.djangoproject.com/en/dev/ref/models/querysets/
Warning Because ManyToManyField attributes and reverse relations can
have multiple related rows, including these can have a multiplier
effect on the size of your result set. This will be especially
pronounced if you include multiple such fields in your values() query,
in which case all possible combinations will be returned.
I want to try to get a result set of n size with with the least amount of database hits authorObject.books.all() would result in at least n db hits.
Is there a way to do this in django?
I think one way of doing this with the least amount of database hits would be to :
authors = Authors.objects.all().values('id')
q = Q()
for id in authors:
q = q | Q(author__id = id)
#m2m author book table.. from my understanding it is
#not accessible in the django QuerySet
author_author_books.filter(q) #grab all of the book ids and author ids with one query
Is there a built in way to query the m2m author_author_books table or am I going to have the write the sql? Is there a way to take advantage of the Q() for doing OR logic in raw sql?
Thanks in advance.
I think you want prefetch_related. Something like this:
authors = Author.objects.prefetch_related('books').all()
More on this here.
If you want to query your author_author_books table, I think you need to specify a "through" table:
class BookAuthor(models.Model):
book = models.ForeignKey(Book)
author = models.ForeignKey(Author)
class Author(models.Model):
name = models.CharField(max_length=127, blank=False)
books = models.ManyToMany(Books, through=BookAuthor)
and then you can query BookAuthor like any other model.
My models look like this:
class Category(models.Model):
name = models.CharField(_('name'), max_length=50)
class Product(models.Model):
name = models.CharField(_('product name'), max_length=40)
category = models.ManyToManyField(Category)
I am trying to build a filter query where I can select 1 or many categories and return products that is connected to all the selected categories.
Example
Product_1 - Belongs to category_1, category_2
Product_2 - Belongs to category_1, category_2 and category_3
When filtering on category_1 and category_2 both products should be returned by the query. When filtering on all 3 categories only Product_2 should be returned since this is the only product related to all selected categories.
The filtering will be dynamic so the number of categories to filter on could be infinite.
How do I do this? I have tried doing
Product.objects.filter(category__in=[1,2,3])
But that gives me both product_1 and product_2 since they match ANY of the categories.
I have tried creating a Q filter
Product.objects.filter(Q(category__id=1), Q(category__id=2))
But this doesn't return any product.
How would a query like this be constructed to work?
I don't know an easy solution for this, but maybe you can use this workaround:
Product.objects.filter(category__in=[1,2,3]).annotate(total=Count('category')).filter(total=3)
Alternatively, you could chain filters:
Product.objects.filter(category=1).filter(category=2).filter(category=3)