Respuestas:
Consulte las preguntas frecuentes sobre documentos: " ¿Cómo puedo ver las consultas SQL sin procesar que Django está ejecutando? "
django.db.connection.queries
contiene una lista de las consultas SQL:
from django.db import connection
print(connection.queries)
Los conjuntos de consultas también tienen un query
atributo que contiene la consulta a ejecutar:
print(MyModel.objects.filter(name="my name").query)
Tenga en cuenta que el resultado de la consulta no es SQL válido, porque:
"Django nunca interpola los parámetros: envía la consulta y los parámetros por separado al adaptador de la base de datos, que realiza las operaciones apropiadas".
Del informe de error Django # 17741 .
Debido a eso, no debe enviar el resultado de la consulta directamente a una base de datos.
str()
función Pythonian incorporada especificada , que invoca el __str__()
método interno . por ejemplo str(MyModel.objects.filter(name="my name").query)
, también recomendaría usar IPython y el shell Django de su proyecto. La finalización de la pestaña proporciona introspección de objetos Como Django es conocido por sus esquemas de nombres asertivos, esta metodología tiende a ser muy útil.
query
SQL no es válida, porque "Django nunca interpola los parámetros: envía la consulta y los parámetros por separado al adaptador de la base de datos, que realiza las operaciones apropiadas". Fuente: code.djangoproject.com/ticket/17741
stable
, no dev
, para vincular a la versión actual de Django, de esta manera: docs.djangoproject.com/en/stable/faq/models/…
Las extensiones Django tienen un comando shell_plus con un parámetroprint-sql
./manage.py shell_plus --print-sql
En django-shell se imprimirán todas las consultas ejecutadas
Ex.:
User.objects.get(pk=1)
SELECT "auth_user"."id",
"auth_user"."password",
"auth_user"."last_login",
"auth_user"."is_superuser",
"auth_user"."username",
"auth_user"."first_name",
"auth_user"."last_name",
"auth_user"."email",
"auth_user"."is_staff",
"auth_user"."is_active",
"auth_user"."date_joined"
FROM "auth_user"
WHERE "auth_user"."id" = 1
Execution time: 0.002466s [Database: default]
<User: username>
Eche un vistazo a debug_toolbar , es muy útil para la depuración.
La documentación y la fuente están disponibles en http://django-debug-toolbar.readthedocs.io/ .
q = Query.objects.values('val1','val2','val_etc')
print q.query
m = MyModel.objects.get(...)
seguido porm.query
m
ya no es un conjunto de consultas. Uso q = MyModel.objects.filter(...)
, entonces q.query
, entonces m = q.get()
.
Ninguna otra respuesta cubre este método, entonces:
Creo que, con mucho, el método más útil, simple y confiable es preguntarle a su base de datos. Por ejemplo, en Linux para Postgres, puede hacer:
sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log
Cada base de datos tendrá un procedimiento ligeramente diferente. En los registros de la base de datos, verá no solo el SQL sin procesar, sino también cualquier configuración de conexión o sobrecarga de transacciones que django está colocando en el sistema.
log_statement='all'
en postgresql.conf
este método.
postgresql.conf
corriendopsql -U postgres -c 'SHOW config_file'
Aunque puede hacerlo con el código suministrado, encuentro que usar la aplicación de la barra de herramientas de depuración es una gran herramienta para mostrar consultas. Puedes descargarlo desde github aquí .
Esto le da la opción de mostrar todas las consultas ejecutadas en una página determinada junto con el tiempo de consulta que tomó. También resume el número de consultas en una página junto con el tiempo total para una revisión rápida. Esta es una gran herramienta, cuando quieres ver lo que hace el Django ORM detrás de escena. También tiene muchas otras características agradables, que puede usar si lo desea.
Otra opción, vea las opciones de registro en settings.py descritas en esta publicación
http://dabapps.com/blog/logging-sql-queries-django-13/
debug_toolbar ralentiza cada carga de página en su servidor de desarrollo, el registro no lo hace así que es más rápido. Las salidas se pueden volcar a la consola o al archivo, por lo que la interfaz de usuario no es tan agradable. Pero para las vistas con muchos SQL, puede llevar mucho tiempo depurar y optimizar los SQL a través de debug_toolbar ya que cada carga de página es muy lenta.
Si se asegura de que su archivo settings.py tenga:
django.core.context_processors.debug
enumerado en CONTEXT_PROCESSORS
DEBUG=True
IP
en la INTERNAL_IPS
tuplaEntonces deberías tener acceso a la sql_queries
variable. Añado un pie de página a cada página que se ve así:
{%if sql_queries %}
<div class="footNav">
<h2>Queries</h2>
<p>
{{ sql_queries|length }} Quer{{ sql_queries|pluralize:"y,ies" }}, {{sql_time_sum}} Time
{% ifnotequal sql_queries|length 0 %}
(<span style="cursor: pointer;" onclick="var s=document.getElementById('debugQueryTable').style;s.disp\
lay=s.display=='none'?'':'none';this.innerHTML=this.innerHTML=='Show'?'Hide':'Show';">Show</span>)
{% endifnotequal %}
</p>
<table id="debugQueryTable" style="display: none;">
<col width="1"></col>
<col></col>
<col width="1"></col>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">SQL</th>
<th scope="col">Time</th>
</tr>
</thead>
<tbody>
{% for query in sql_queries %}
<tr class="{% cycle odd,even %}">
<td>{{ forloop.counter }}</td>
<td>{{ query.sql|escape }}</td>
<td>{{ query.time }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
Obtuve la variable sql_time_sum
agregando la línea
context_extras['sql_time_sum'] = sum([float(q['time']) for q in connection.queries])
a la función de depuración en django_src / django / core / context_processors.py.
Desarrollé una extensión para este propósito, para que pueda poner fácilmente un decorador en su función de vista y ver cuántas consultas se ejecutan.
Instalar:
$ pip install django-print-sql
Para usar como administrador de contexto:
from django_print_sql import print_sql
# set `count_only` to `True` will print the number of executed SQL statements only
with print_sql(count_only=False):
# write the code you want to analyze in here,
# e.g. some complex foreign key lookup,
# or analyzing a DRF serializer's performance
for user in User.objects.all()[:10]:
user.groups.first()
Para usar como decorador:
from django_print_sql import print_sql_decorator
@print_sql_decorator(count_only=False) # this works on class-based views as well
def get(request):
# your view code here
Creo que esto debería funcionar si está utilizando PostgreSQL:
from django.db import connections
from app_name import models
from django.utils import timezone
# Generate a queryset, use your favorite filter, QS objects, and whatnot.
qs=models.ThisDataModel.objects.filter(user='bob',date__lte=timezone.now())
# Get a cursor tied to the default database
cursor=connections['default'].cursor()
# Get the query SQL and parameters to be passed into psycopg2, then pass
# those into mogrify to get the query that would have been sent to the backend
# and print it out. Note F-strings require python 3.6 or later.
print(f'{cursor.mogrify(*qs.query.sql_with_params())}')
Lo siguiente devuelve la consulta como SQL válido, basado en https://code.djangoproject.com/ticket/17741 :
def str_query(qs):
"""
qs.query returns something that isn't valid SQL, this returns the actual
valid SQL that's executed: https://code.djangoproject.com/ticket/17741
"""
cursor = connections[qs.db].cursor()
query, params = qs.query.sql_with_params()
cursor.execute('EXPLAIN ' + query, params)
res = str(cursor.db.ops.last_executed_query(cursor, query, params))
assert res.startswith('EXPLAIN ')
return res[len('EXPLAIN '):]
He hecho un pequeño fragmento que puedes usar:
from django.conf import settings
from django.db import connection
def sql_echo(method, *args, **kwargs):
settings.DEBUG = True
result = method(*args, **kwargs)
for query in connection.queries:
print(query)
return result
# HOW TO USE EXAMPLE:
#
# result = sql_echo(my_method, 'whatever', show=True)
Toma como función de parámetros (contiene consultas sql) para inspeccionar y args, kwargs necesarios para llamar a esa función. Como resultado, devuelve qué función devuelve e imprime consultas SQL en una consola.
Puse esta función en un archivo util en una de las aplicaciones de mi proyecto:
import logging
import re
from django.db import connection
logger = logging.getLogger(__name__)
def sql_logger():
logger.debug('TOTAL QUERIES: ' + str(len(connection.queries)))
logger.debug('TOTAL TIME: ' + str(sum([float(q['time']) for q in connection.queries])))
logger.debug('INDIVIDUAL QUERIES:')
for i, query in enumerate(connection.queries):
sql = re.split(r'(SELECT|FROM|WHERE|GROUP BY|ORDER BY|INNER JOIN|LIMIT)', query['sql'])
if not sql[0]: sql = sql[1:]
sql = [(' ' if i % 2 else '') + x for i, x in enumerate(sql)]
logger.debug('\n### {} ({} seconds)\n\n{};\n'.format(i, query['time'], '\n'.join(sql)))
Luego, cuando sea necesario, solo lo importo y lo llamo desde cualquier contexto (generalmente una vista) es necesario, por ejemplo:
# ... other imports
from .utils import sql_logger
class IngredientListApiView(generics.ListAPIView):
# ... class variables and such
# Main function that gets called when view is accessed
def list(self, request, *args, **kwargs):
response = super(IngredientListApiView, self).list(request, *args, **kwargs)
# Call our function
sql_logger()
return response
Es bueno hacer esto fuera de la plantilla porque si tiene vistas de API (generalmente Django Rest Framework), también es aplicable allí.
Para Django 2.2:
Como la mayoría de las respuestas no me ayudaron mucho al usar ./manage.py shell
. Finalmente encontré la respuesta. Espero que esto ayude a alguien.
Para ver todas las consultas:
from django.db import connection
connection.queries
Para ver la consulta de una sola consulta:
q=Query.objects.all()
q.query.__str__()
q.query
solo mostrando el objeto para mí. El uso de __str__()
(Representación de cadena) muestra la consulta completa.
Ver consultas usando django.db.connection.queries
from django.db import connection
print(connection.queries)
Acceda a la consulta SQL sin procesar en el objeto QuerySet
qs = MyModel.objects.all()
print(qs.query)
Solo para agregar, en django, si tiene una consulta como:
MyModel.objects.all()
hacer:
MyModel.objects.all().query.sql_with_params()
para obtener la cadena sql