Django nested query in From clause - django

Is there any way to construct a query like the following using Django ORM?
SELECT * from ( SELECT r1 from table_name ) temp;

You can use Subquery as the docs says.
Here is an example:
from django.db.models import Subquery
Table.objects.filter(id__in=Subquery(Table2.objects.filter(...).values_list("table_id", flat=True)))

Related

Annotating without using Exists or SubQuery

I have a client who is using Django 1.8. While they will be moved to the latest version, we need to run some queries before their migration, but obviously we can't use Exists or OuterRef.
In our case we want to annotate a queryset. eg
recordset = Question.objects.annotate(
has_answers=Exists(Answers.objects.filter(question=OuterRef('pk')))
)
Is there a workaround to do the equivalent of the above annotation. What did people use in 'the olden days'?
The following should work in 1.8, annotate each question with the count of answers and then use a conditional expression to convert that to a boolean
from django.db.models import Count, Case, When, BooleanField
Question.objects.annotate(
num_answers=Count('answer')
).annotate(
has_answers=Case(
When(num_answers__gt=0, then=True),
default=False,
output_field=BooleanField()
)
)

JOIN on django orm

1.
1.1. query:
QuestionRequestAnswerModel.objects.filter(request_no__exact=index['id']).select_related('answer_user').values('answer_user', 'amount', 'select_yn')
2.
2.1. query:
QuestionRequestAnswerModel.objects.filter(request_no__exact=index['id']).select_related('answer_user')[0].answer_user
description
I want to get answer_user's last_name.
but when I use django orm by select_realated('answer_user'),
the result give me the answer_user's id only.
how can I get another column, except id, on ORM join?
You can follow foreign key relationships in value queries by using the double underscore notation
QuestionRequestAnswerModel.objects.filter(
request_no__exact=index['id']
).select_related(
'answer_user'
).values(
'answer_user__last_name',
'amount',
'select_yn'
)

"SELECT DISTINCT field_name from table" Django using raw sql

How can I run SELECT DISTINCT field_name from table; SQL query in Django as raw sql ?
When I try to use Table.objects.raw("""SELECT DISTINCT field_name from table"""), I got an exception as
InvalidQuery: Raw query must include the primary key
If you don't need the model instances (which are useless if you want a single field), you can as well just use a plain db-api cursor:
from django.db import connection
cursor = connection.cursor()
cursor.execute("select distinct field from table")
for row in cursor:
print(row[0])
But for your example use case you don't need SQL at all - the orm has values and values_list querysets and a distinct() modifier too:
queryset = YourModel.objects.values_list("field", flat=True).order_by("field").distinct()
print(str(queryset.query))
# > 'SELECT DISTINCT `table`.`field` FROM `table` ORDER BY `table`.`title` ASC'
for title in queryset:
print(title)
NB :
1/ since we want single field, I use the flat=True argument to avoid getting a list of tuples
2/ I explicitely set the ordering on the field else the default ordering eventually defined in the model's meta could force the ordering field to be part of te generated query too.
Looks like you have to use some workaround
select field_name, max(id)
from table_name
group by field_name;

Django Postgresql ArrayField aggregation

In my Django application, using Postgresql, I have a model with an ArrayField of CharFields.
I would like to know if there's a DB way to aggregate and get a list of all the strings in the table. For example:
['dog', 'cat']
['dog']
['cat']
would yield ['dog', 'cat']
I know how to do that in Python but would like to find out a way to aggregate this on the DB level.
Using Django 1.8.4
In PostgreSQL you can do the following:
SELECT DISTINCT UNNEST(array_column) FROM the_table;
So if your model looks something like
class TheModel(models.Model):
# ...
array_field = ArrayField(models.CharField(max_length=255, blank=True),\
default=list)
# ...
the Django equivalent is:
from django.db.models import Func, F
TheModel.objects.annotate(arr_els=Func(F('array_field'), function='unnest'))\
.values_list('arr_els', flat=True).distinct()

change raw query into django models

i want to use django models feature to excute this sql query.
SELECT COUNT(DISTINCT ques_id), title FROM contest_assignment WHERE grp_id = 60 GROUP BY title;
i tried this but it did not give me proper result:
from django.db.models import Count
assignment.objects.values_list('title').annotate(count=Count('ques')).values('title', 'count')
how can i use django model?
You shouldn't use both .values() and .values_list(). The count field is implicitly added to the set of fields that is returned.
Django supports a COUNT(DISTINCT <field>) query by using .annotate(count=Count('<field>', distinct=True)). That would leave you with the following query:
(assignment.objects.filter(grp_id=60).values('title')
.annotate(count=Count('ques_id', distinct=True)))