class Post(models.Model):
created_time = models.DateTimeField()
comment_count = models.IntegerField(default=0)
like_count = models.IntegerField(default=0)
group = models.ForeignKey(Group)
class MonthPost(models.Model):
created_time = models.DateTimeField()
comment_count = models.IntegerField(default=0)
like_count = models.IntegerField(default=0)
group = models.ForeignKey(Group)
post = models.OneToOneField(Post)
I use this two models. MonthPost is part of Post.
I want to use MonthPost when filtered date is smaller than month.
_models = Model.extra(
select={'score': 'like_count + comment_count'},
order_by=('-score',)
)
I use extra about above two models. Post works well, but MonthPost doesn't work.
django.db.utils.ProgrammingError: column reference "like_count" is ambiguous
LINE 1: ... ("archive_post"."is_show" = false)) ORDER BY (like_count...
This is the error message.
_models.values_list("post", flat=True)
And then, I want to extract OneToOne field(post) from MonthPost.
I try to use values_list("post", flat=True). It return only id list.
I need to post object list for django rest framework.
I don't' quite understand what you are trying to achieve with your MonthPost model and why it duplicates Post fields. With that being said I think you can get the results you want with this info.
First of all extra is depreciated see the docs on extra. In either case, your select is not valid SQL syntax, your query should look more like this:
annotate(val=RawSQL(
"select col from sometable where othercol =%s",
(someparam,)))
However, what you are after here requires neither extra or RawSql. These methods should only be used when there is no built in way to achieve the desired results. When using RawSql or extra, you must tailor the SQL for your specific backed. Django has built in methods for such queries:
qs = Post.objects.all().annotate(
score=(Count('like_count') + Count('comment_count'))
A values_list() query needs to explicitly list all fields from related models and extra or annotated fields. For MonthPost it should look like this:
MonthPost.objects.all().values_list('post', 'post__score', 'post__created_time')
Finally, if the purpose of MonthPost is simply to list the posts with he greatest score for a given month, you can eliminate the MonthPost model entirely and query your Post model for this.
import datetime
today = datetime.date.today()
# Filter for posts this month
# Annotate the score
# Order the results by the score field
qs = Post.objects\
.filter(created_time__year=today.year, created_time__month=today.month)\
.annotate(score=(Count('like_count') + Count('comment_count'))\
.order_by('score')
# Slice the top ten posts for the month
qs = qs[:10]
The code above is not tested, but should give you a better handle on how to perform these types of queries.
Related
Given these models
class User(Model):
pass
class Post(Model):
by = ForeignKey(User)
posted_on = models.DateTimeField(auto_now=True)
I want to get the latest Posts, but not all from the same User, I have something like this:
posts = Post.objects.filter(public=True) \
.order_by('posted_on') \
.distinct("by")
But distinct doesn't work on mysql, I'm wondering if there is another way to do it?
I have seen some using values(), but values doesn't work for me because I need to do more things with the objects themselves
Since distinct will not work with MySQL on other fields then model id, this is possible way-around with using Subquery:
from django.db.models import Subquery, OuterRef
...
sub_qs = Post.objects.filter(user_id=OuterRef('id')).order_by('posted_on')
# here you get users with annotated last post
qs = User.objects.annotate(last_post=Subquery(sub_qs[:1]))
# next you can limit the number of users
Also note that ordering on posted_on field depends on your model constraints - perhaps you'll need to change it to -posted_on to order from newest on top.
order_by should match the distinct(). In you case, you should be doing this:
posts = Post.objects.filter(public=True) \
.order_by('by') \
.distinct('by')
.distinct([*fields]) only works in PostgresSQL.
For MySql Engine. This is MySQL documentation in Django:
Here's the difference. For a normal distinct() call, the database
compares each field in each row when determining which rows are
distinct. For a distinct() call with specified field names, the
database will only compare the specified field names.
For MySql workaround could be this:
from django.db.models import Subquery, OuterRef
user_post = Post.objects.filter(user_id=OuterRef('id')).order_by('posted_on')
post_ids = User.objects.filter(related_posts__isnull=False).annotate(post=Subquery(user_post.values_list('id', flat=True)[:1]))).values_list('post', flat=True)
posts = Post.objects.filter(id__in=post_ids)
I've have an issue regarding queries with a group by clause.
Lets assume I have the following Django-Model:
class SomeModel(models.Model):
date = models.DateField()
value = models.FloatField()
relation = models.ForeignKey('OtherModel')
If I want to do a query where I group SomeModel instances by OtherModel and annotate the latest date:
SomeModel.objects.values('relation').annotate(Max('date'))
This is all great, but as soon as I want to add a filter on the already annotated queryset I am getting nowhere:
SomeModel.objects.values('relation').annotate(Max('date')).filter(value__gt=0)
This would indeed filter out all the value != 0, however I only want it after the annotations took place. If the latest date of a relation has the value 0, I want it to be filtered out!
You need to add the value in the annotate filed and then you can filter over it. Your ORM query becomes
SomeModel.objects.values('relation').annotate(Max('date'), value=F('value')).filter(value__gt=0)
This should give the value you require
Let's say we have a two models like these:
Artist(models.Model):
name = models.CharField(max_length=50)
Track(models.Model):
title = models.CharField(max_length=50)
artist = models.ForeignKey(Artist, related_name='tracks')
How can I filter this relationship to get the first foreign record?
So I've tried something like this, but it didn't work (as expected)
artists = Artist.objects.filter(tracks__first__title=<some-title>)
artists = Artist.objects.filter(tracks[0]__title=<some-title>)
Is there any way to make this work?
Here's a solution not taking performance into consideration.
Artist.objects.filter(tracks__in=[a.tracks.first() for a in Artist.objects.all()], tracks__title=<some_title>)
No list approach, as requested.
Artist.objects.filter(tracks__in=Track.objects.all().distinct('artist').order_by('artist', 'id'), tracks__title=<some_title>)
The order_by 'id' is important to make sure distinct gets the first track based on insertion. The order_by 'artist' is a requirement for sorting distinct queries. Read about it here: https://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-DISTINCT
I have two tables 'Contact' and other is "Subscriber".. I want to Compare Contact_id of both and want to show only those Contact_id which is present in Contact but not in Subscriber.These two tables are in two different Models.
Something like this should work:
Contact.objects.exclude(
id__in=Subscriber.objects.all()
).values_list('id', flat=True)
Note that these are actually two SQL queries. I'm sure there are ways to optimize it, but this will usually work fine.
Also, the values_list has nothing to do with selecting the objects, it just modifies "format" of what is returned (list of IDs instead of queryset of objects - but same database records in both cases).
If you are excluding by some field other then Subscriber.id (e.g: Subscriber.quasy_id):
Contact.objects.exclude(
id__in=Subscriber.objects.all().values_list('quasy_id', flat=True)
).values_list('id', flat=True)
Edit:
This answer assumes you don't have a relationship between your Contact and Subscriber models. If you do, then see #navit's answer, it is a better choice.
Edit 2:
That flat=True inside exclude is actually not needed.
I assume you have your model like this:
class Subscriber(models.Model):
contact = models.ForeignKey(Contact)
You can do what you want like this:
my_list = Subscriber.objects.filter(contact=None)
This retrieves Subscribers which don't have a Contact. Retrieveing a list of Contacts is straightforward.
If you want to compare value of fields in two different tables(which have connection with ForeignKey) you can use something like this:
I assume model is like below:
class Contact(models.Model):
name = models.TextField()
family = models.TextField()
class Subscriber(models.Model):
subscriber_name = models.ForeignKey(Contact, on_delete=models.CASCADE)
subscriber_family = models.TextField()
this would be the query:
query = Subscriber.objects.filter(subscriber_name =F(Contact__name))
return query
I have the following model defined in models.py
class Schoolclass(models.Model):
...
date_created = models.DateTimeField('date created')
In my views.py I want to order the list of Schoolclass objects by the year only associated with date_created. I specifically don't want ordering to take account of any other element of the DateTimeField. The reason being that I wish secondary ordering to occur through a different field.
This is what I can come up with but it doesn't work.
def index(request):
class_list = SchoolClass.objects.order_by('date_created__year')
In case it helps I get the following error when I run the above code:
Join on field 'date_created' not permitted. Did you misspell 'year' for the lookup type?
The problem is that the year field only exists in Python, not in the database. I guess you'll have to use extra() and make it explicit to the database that it should order by the year part of the datetime field. How exactly to do that will depend on your database.
This should work for MySQL:
def index(request):
class_list = SchoolClass.objects.extra(select={'year_created': 'YEAR(date_created)'},
order_by=['year_created'])
If you're using other database, you'll have to replace YEAR(date_created) with the equivalent operation to extract the year from a datetime field.