Gibt es eine Möglichkeit, die SQL, die Django ausgeführt wird, während der Durchführung einer Abfrage zu zeigen?
Antworten
Zu viele Anzeigen?Es gibt noch eine andere Möglichkeit, die sehr nützlich ist, wenn Sie die Abfrage für ein benutzerdefiniertes SQL wiederverwenden müssen. Ich habe dies in einer Analyse-App verwendet, die weit über das hinausgeht, was Djangos ORM bequem tun kann, also schließe ich ORM-generiertes SQL als Unterabfragen ein.
from django.db import connection
from myapp.models import SomeModel
queryset = SomeModel.objects.filter(foo='bar')
sql_query, params = queryset.query.as_sql(None, connection)
Dadurch erhalten Sie das SQL mit Platzhaltern sowie ein Tupel mit den zu verwendenden Abfrageparametern. Dieses können Sie direkt an die DB weitergeben:
with connection.connection.cursor(cursor_factory=DictCursor) as cursor:
cursor.execute(sql_query, params)
data = cursor.fetchall()
Ich habe ein kleines Snippet erstellt, das Sie verwenden können:
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)
Sie nimmt als Parameter die Funktion (enthält SQL-Abfragen), die überprüft werden soll, und die für den Aufruf dieser Funktion erforderlichen Args und Wargs. Als Ergebnis gibt es zurück, was die Funktion zurückgibt und druckt SQL-Abfragen in einer Konsole.
Um die Ergebnisabfrage von django an die Datenbank (mit korrekter Parametersubstitution) können Sie diese Funktion verwenden:
from django.db import connection
def print_database_query_formatted(query):
sql, params = query.sql_with_params()
cursor = connection.cursor()
cursor.execute('EXPLAIN ' + sql, params)
db_query = cursor.db.ops.last_executed_query(cursor, sql, params).replace('EXPLAIN ', '')
parts = '{}'.format(db_query).split('FROM')
print(parts[0])
if len(parts) > 1:
parts = parts[1].split('WHERE')
print('FROM{}'.format(parts[0]))
if len(parts) > 1:
parts = parts[1].split('ORDER BY')
print('WHERE{}'.format(parts[0]))
if len(parts) > 1:
print('ORDER BY{}'.format(parts[1]))
# USAGE
users = User.objects.filter(email='admin@admin.com').order_by('-id')
print_database_query_formatted(users.query)
Beispiel für die Ausgabe
SELECT "users_user"."password", "users_user"."last_login", "users_user"."is_superuser", "users_user"."deleted", "users_user"."id", "users_user"."phone", "users_user"."username", "users_user"."userlastname", "users_user"."email", "users_user"."is_staff", "users_user"."is_active", "users_user"."date_joined", "users_user"."latitude", "users_user"."longitude", "users_user"."point"::bytea, "users_user"."default_search_radius", "users_user"."notifications", "users_user"."admin_theme", "users_user"."address", "users_user"."is_notify_when_buildings_in_radius", "users_user"."active_campaign_id", "users_user"."is_unsubscribed", "users_user"."sf_contact_id", "users_user"."is_agree_terms_of_service", "users_user"."is_facebook_signup", "users_user"."type_signup"
FROM "users_user"
WHERE "users_user"."email" = 'admin@admin.com'
ORDER BY "users_user"."id" DESC
Sie basiert auf diesem Ticket-Kommentar: https://code.djangoproject.com/ticket/17741#comment:4
An SQL generieren para CREATE / UPDATE Befehle, die sofort in Django [getestet auf 1.8]
def generate_update_sql(queryset, update_kwargs):
"""Converts queryset with update_kwargs
like if was: queryset.update(**update_kwargs)
qs = Event.objects.exclude(app='some')
update_kwargs = dict(description='test', action='action')
generate_update_sql(qs, update_kwargs) will return
UPDATE `api_event` SET `description` = test, `action` = action WHERE NOT (`api_event`.`app` = some)
"""
from django.db.models import sql
query = queryset.query.clone(sql.UpdateQuery)
query.add_update_values(update_kwargs)
compiler = query.get_compiler(queryset.db)
sql, params = compiler.as_sql()
return sql % params
def generate_create_sql(model, model_data):
"""Converts queryset with create_kwargs
like if was: queryset.create(**create_kwargs)
generate_create_sql(Event, dict(slug='a', app='b', model='c', action='e')) will return
"INSERT INTO `api_event` (`slug`, `app`, `model`, `action`, `action_type`) VALUES (a, b, c, e, )"
"""
from django.db.models import sql
not_saved_instance = model(**model_data)
not_saved_instance._for_write = True
query = sql.InsertQuery(model)
fields = [f for f in model._meta.local_concrete_fields if not isinstance(f, AutoField)]
query.insert_values(fields, [not_saved_instance], raw=False)
compiler = query.get_compiler(model.objects.db)
sql, params = compiler.as_sql()[0]
return sql % params
Tests und Verwendung
def test_generate_update_sql_with_F(self):
qs = Event.objects.all()
update_kwargs = dict(description=F('slug'))
result = generate_update_sql(qs, update_kwargs)
sql = "UPDATE `api_event` SET `description` = `api_event`.`slug`"
self.assertEqual(sql, result)
def test_generate_create_sql(self):
result = generate_create_sql(Event, dict(slug='a', app='b', model='c', action='e'))
sql = "INSERT INTO `api_event` (`slug`, `app`, `model`, `action`, `action_type`, `description`) VALUES (a, b, c, e, , )"
self.assertEqual(sql, result)