Getting the SQL from a Django QuerySet - python

How do I get the SQL that Django will use on the database from a QuerySet object? I'm trying to debug some strange behavior, but I'm not sure what queries are going to the database.

You print the queryset's query attribute.
>>> queryset = MyModel.objects.all()
>>> print(queryset.query)
SELECT "myapp_mymodel"."id", ... FROM "myapp_mymodel"

Easy:
print(my_queryset.query)
For example:
from django.contrib.auth.models import User
print(User.objects.filter(last_name__icontains = 'ax').query)
It should also be mentioned that if you have DEBUG = True, then all of your queries are logged, and you can get them by accessing connection.queries:
from django.db import connections
connections['default'].queries
The django debug toolbar project uses this to present the queries on a page in a neat manner.

The accepted answer did not work for me when using Django 1.4.4. Instead of the raw query, a reference to the Query object was returned: <django.db.models.sql.query.Query object at 0x10a4acd90>.
The following returned the query:
>>> queryset = MyModel.objects.all()
>>> queryset.query.__str__()

This middleware will output every SQL query to your console, with color highlighting and execution time, it's been invaluable for me in optimizing some tricky requests
http://djangosnippets.org/snippets/290/

As an alternative to the other answers, django-devserver outputs SQL to the console.

Related

Django queryset return DurationField value in seconds

I have two models: Post, Comment (Comment has FK relation to Post).
Now I want to return all posts with theirs "response time". I get this response time in timedelta format. Can I receive it in seconds instead? I tried ExtractSecond but it is not what I'm looking for:
base_posts_queryset.annotate(
min_commnet_date=Min("comment_set__date_created"),
response_time=ExpressionWrapper(F("min_commnet_date") - F("date_created"), output_field=DurationField()),
response_time_in_sec=ExtractSecond(F("response_time"))
).filter(response_time__isnull=False).values("response_time", "response_time_in_sec")
This code returns following objects:
{'response_time': datetime.timedelta(days=11, seconds=74024, microseconds=920107), 'response_time_in_sec': 44}
What I want to achieve is basically call .seconds for each item in result queryset. I could do this in python, but mb it could be done on db level?
Sure can, but the exact mechanism may depend upon your database.
In postgres, you can use EXTRACT(epoch FROM <interval>) to get the total number of seconds.
To use this in Django, you can create a Func subclass:
class Epoch(django.db.models.expressions.Func):
template = 'EXTRACT(epoch FROM %(expressions)s)::INTEGER'
output_field = models.IntegerField()
Then you can use it directly:
base_posts.annotate(
response_time_sec=Epoch(F('min_comment_date') - F('date_created'))
)
Nice solution!
One wrinkle is that I think there is a missing 's' needed to get this to work in Django 3
class Epoch(django.db.models.expressions.Func):
template = 'EXTRACT(epoch FROM %(expressions)s)::INTEGER'
output_field = models.IntegerField()
As already answered here, it depends upon your database. As stated in Django documentation of Extract method:
Django usually uses the databases’ extract function, so you may use any lookup_name that your database supports.
So for example with PostgreSQL:
response_time_in_sec=Extract(F("response_time"), "epoch")

And operator in a Django filter

I created a Django Rest Framework API endpoint. I would like this endpoint to retrieve all the records with the Status field set to Free, so i did this:
queryset = tst.objects.using('screener').filter(Status=Free)
Now, i want to retrieve not only the fields with the field set to Free, but also those with the status set to Pending.
I tried this:
class tstList(generics.ListCreateAPIView):
criterion1 = Q(Status="Free")
criterion2 = Q(Status="Pending")
queryset = tst.objects.using('screener').filter(criterion1&criterion2)
For some reason, this view will retrieve nothing. If i try the queries individually, though, they will work:
queryset = tst.objects.using('screener').filter(criterion1) #works
use this
queryset = tst.objects.using('screener').filter(criterion1|criterion2)
right now in filter you are using and condition but you need a or condition
for more information you can read this article
You probably don't want the & operator but the or (|)
https://docs.python.org/3.8/library/stdtypes.html#boolean-operations-and-or-not

Why .query() function not working on Django ORM query?

As I already know that using .query.__str__() , we can get sql equivalent query from Django ORM query.
e.g : Employees.objects.filter(id = int(id)).query.__str__()
Above code working well & I am able to get sql equivalent query
but when I am using same on below query I am getting error like below.
Employees.objects.filter(id = int(id)).first().query.__str__()
AttributeError: 'Employees' object has no attribute 'query'
Why now I am getting error, any suggestions ?
.first() [Django-doc] does not return a QuerySet, it returns a model object. The query is evaluated eagerly.
You can inspect the last query that Django made with:
from django.db import connection
print(connection.queries[-1:])
That being said, in essence a some_queryset.first() is often the same query as some_queryset, except that it will limit the queryset.
Note: Please do not use .__str__, you can use str(my_queryset.query), or just print(my_queryset.query).

Mongoengine: create a QuerySet from a MongoDB cursor

Some part of the application I'm working in is expecting a mongoengine QuerySet.
I have a MongoDB cursor with the info I need, generated by an aggregation.
Since mongoengine documentation specifies that a QuerySet is a wrapper of a MongoDB cursor, is there any way to create a QuerySet with a given cursor?
Note: There is an obvious solution, querying the database again:
queryset = Model.objects.filter(_id__in=[r['_id'] for r in cursor])
But it's rather ugly. The ideal solution would be something like calling the constructor of QuerySet, since it is a wrapper of cursor. But constructor does not accept cursor as an argument.
QuerySet is nothing but just a list. So you can convert the output you get from aggregating into a list like below and directly use that list as QuerySet.
queryset = list(cursor)

Django Query only one field of a model using .extra() and without using .defer() or .only()

I'm using django ORM's exact() method to query only selected fields from a set of models to save RAM. I can't use defer() or only() due to some constraints on the ORM manager I am using (it's not the default one).
The following code works without an error:
q1 = Model.custom_manager.all().extra(select={'field1':'field1'})
# I only want one field from this model
However, when I jsonify the q1 queryset, I get every single field of the model.. so extra() must not have worked, or am I doing something wrong?
print SafeString(serializers.serialize('json', q1))
>>> '{ everything!!!!!}'
To be more specific, the custom manager I am using is django-sphinx. Model.search.query(...) for example.
Thanks.
So, Im not sure if you can do exactly what you want to do. However, if you only want the values for a particular field or a few fields, you can do it with values
It likely does the full query, but the result will only have the values you want. Using your example:
q1 = Model.custom_manager.values('field1', 'field2').all()
This should return a ValuesQuerySet. Which you will not be able to use with serializers.serialize so you will have to do something like this:
from django.utils import simplejson
data = [value for value in q1]
json_dump = simplejson.dumps(data)
Another probably better solution is to just do your query like originally intended, forgetting extra and values and just use the fields kwarg in the serialize method like this:
print SafeString(serializers.serialize('json', q1, fields=('field1', 'field2')))
The downside is that none of these things actually do the same thing as Defer or Only(all the fields are returned from the database), but you get the output you desire.

Categories