-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
817 additions
and
156 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,314 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<meta name="author" content="Thomas Loiret"> | ||
<meta name="description" content="6 different ways to see the SQL generated by Django."> | ||
|
||
<meta name="twitter:card" content="summary_large_image"> | ||
<meta name="twitter:site" content="@b0uh"> | ||
<meta name="twitter:creator" content="@b0uh"> | ||
<meta name="twitter:title" content="Django: show me the SQL - Thomas Loiret - Random thoughts"> | ||
<meta name="twitter:description" content="6 different ways to see the SQL generated by Django."> | ||
<meta name="twitter:image" content="https://b0uh.github.io/medias/show-me-what-you-got-rick-and-morty.png"> | ||
|
||
<meta name="google-site-verification" content="jZBc2U9MHiBnSlgpoFEed-V3PZ16pMNv0GSX4hOh4mg" /> | ||
|
||
<title>Django: show me the SQL - Thomas Loiret - Random thoughts</title> | ||
|
||
<!-- Custom styles for this template --> | ||
<!-- build:css stylesheets/main.css --> | ||
<link rel="stylesheet" href="https://b0uh.github.io/theme/css/main.min.css"> | ||
<link rel="stylesheet" href="https://b0uh.github.io/theme/css/custom.min.css"> | ||
<link rel="stylesheet" href="https://b0uh.github.io/theme/css/pygments/autumn.min.css"> | ||
|
||
<!-- endbuild --> | ||
|
||
<link href="https://b0uh.github.io/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Thomas Loiret - Random thoughts Atom Feed" /> | ||
|
||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> | ||
<!--[if lt IE 9]> | ||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> | ||
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> | ||
<![endif]--> | ||
|
||
<!-- Google Fonts --> | ||
<script type="text/javascript"> | ||
WebFontConfig = { | ||
google: { families: [ 'Open+Sans:300,400,700:latin', 'Lato:700,900:latin' ] } | ||
}; | ||
(function() { | ||
var wf = document.createElement('script'); | ||
wf.src = ('https:' == document.location.protocol ? 'https' : 'http') + | ||
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js'; | ||
wf.type = 'text/javascript'; | ||
wf.async = 'true'; | ||
var s = document.getElementsByTagName('script')[0]; | ||
s.parentNode.insertBefore(wf, s); | ||
})(); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
<!-- header --> | ||
<header class="header push-down-45"> | ||
<div class="container"> | ||
|
||
<!-- Brand and toggle get grouped for better mobile display --> | ||
<div class="navbar-header"> | ||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#readable-navbar-collapse"> | ||
<span class="sr-only">Toggle navigation</span> | ||
<span class="icon-bar"></span> | ||
<span class="icon-bar"></span> | ||
<span class="icon-bar"></span> | ||
</button> | ||
</div> | ||
|
||
<nav class="navbar navbar-default" role="navigation"> | ||
<!-- Collect the nav links, forms, and other content for toggling --> | ||
<div class="collapse navbar-collapse" id="readable-navbar-collapse"> | ||
<ul class="navigation"> | ||
|
||
<li> | ||
<a href="https://b0uh.github.io">Home</a> | ||
</li> | ||
|
||
<li> | ||
<a href="https://b0uh.github.io/pages/about.html">About</a> | ||
</li> | ||
<li> | ||
<a href="https://b0uh.github.io/pages/bookmarks.html">Bookmarks</a> | ||
</li> | ||
|
||
<li> | ||
<a href="https://b0uh.github.io/archives.html">Archives</a> | ||
</li> | ||
|
||
</ul> | ||
</div><!-- /.navbar-collapse --> | ||
</nav> | ||
|
||
<div class="hidden-xs hidden-sm"> | ||
<div class="social"> | ||
<a href="#" class="search__container"> | ||
<span class="glyphicon glyphicon-flash"></span> | ||
</a> | ||
<ul class="social__dropdown"> | ||
<li> | ||
<a href="https://b0uh.github.io/feeds/all.atom.xml" target="_blank" class="social__container"> | ||
<span class="zocial-rss"></span> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://mamot.fr/@b0uh" rel="me" target="_blank" class="social__container"> | ||
<img src="https://b0uh.github.io/theme/images/icons/mastodon-25px.png" /> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://twitter.com/b0uh" target="_blank" class="social__container"> | ||
<span class="zocial-twitter"></span> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.linkedin.com/in/thomasloiret/" target="_blank" class="social__container"> | ||
<span class="zocial-linkedin"></span> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.last.fm/user/b0uh" target="_blank" class="social__container"> | ||
<span class="zocial-lastfm"></span> | ||
</a> | ||
</li> | ||
</ul> | ||
</div> | ||
</div> | ||
</div> | ||
</header> | ||
|
||
<div class="container"> | ||
|
||
<div itemscope itemtype="http://schema.org/Article" class="boxed push-down-60"> | ||
|
||
<div class="meta"> | ||
<img itemprop="image" class="wp-post-image" src="https://b0uh.github.io/medias/show-me-what-you-got-rick-and-morty.png" alt="Django: show me the SQL" width="1138" height="493"> | ||
<div class="meta__container"></div> | ||
</div> | ||
|
||
<!-- Start of the blogpost --> | ||
<div class="row"> | ||
<div class="col-xs-10 col-xs-offset-1 col-md-8 col-md-offset-2 push-down-60"> | ||
|
||
<!-- Start of the content --> | ||
<div class="post-content"> | ||
|
||
<h1 itemprop="name">Django: show me the SQL</h1> | ||
|
||
<div class="meta__container--without-image"> | ||
<div class="row"> | ||
<div class="col-xs-12 col-sm-8"> | ||
<span itemprop="author" itemscope itemtype="http://schema.org/Person"> | ||
<div class="meta__info" itemprop="name"> | ||
Thomas Loiret | ||
</div> | ||
</span> | ||
</div> | ||
<div class="col-xs-12 col-sm-4"> | ||
<div class="meta__comments"> | ||
<span class="meta__date" itemprop="datePublished" content="2024-02-28"> | ||
<span class="glyphicon glyphicon-calendar"></span> Wed 28 February 2024 | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<span itemprop="articleBody"> | ||
<p>Here are 6 different ways of inspecting the SQL generated by the ORM of Django.</p> | ||
<ol> | ||
<li><a href="#anchor-using-query-attribute">Using the <code>query</code> attribute</a></li> | ||
<li><a href="#anchor-using-connection-queries">Using <code>connection.queries</code></a></li> | ||
<li><a href="#anchor-in-the-logs">In the logs</a></li> | ||
<li><a href="#anchor-using-django-debug-toolbar">Using Django Debug Toolbar</a></li> | ||
<li><a href="#anchor-django-extensions-shell-plus">Using django-extensions and shell_plus</a></li> | ||
<li><a href="#anchor-django-extentions-runserver-plus">Using django-extensions and runserver_plus</a></li> | ||
</ol> | ||
<h1>Using the <code>query</code> attribute<a id="anchor-using-query-attribute"></a></h1> | ||
<ol> | ||
<li>Add <code>.query</code> to your queryset. For example:</li> | ||
</ol> | ||
<div class="highlight"><pre><span></span><code><span class="n">qs</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">"gustave"</span><span class="p">)</span> | ||
<span class="nb">print</span><span class="p">(</span><span class="n">qs</span><span class="o">.</span><span class="n">query</span><span class="p">)</span> | ||
</code></pre></div> | ||
|
||
<p><strong>Note:</strong> this does not work for the expressions that do not return a QuerySet. For example, those ending with <code>.count()</code> or <code>.exists()</code>.</p> | ||
<h1>Using <code>connection.queries</code><a id="anchor-using-connection-queries"></a></h1> | ||
<ol> | ||
<li>In your Django settings make sure <code>DEBUG</code> is set to <code>True</code></li> | ||
<li>In your code do:</li> | ||
</ol> | ||
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">connection</span><span class="p">,</span> <span class="n">reset_queries</span> | ||
<span class="c1"># reset_queries() # Optional, will empty the query list</span> | ||
<span class="nb">print</span><span class="p">(</span><span class="n">connection</span><span class="o">.</span><span class="n">queries</span><span class="p">)</span> | ||
</code></pre></div> | ||
|
||
<p>Official documentation: <a href="https://docs.djangoproject.com/en/5.0/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running">here</a></p> | ||
<h1>In the logs<a id="anchor-in-the-logs"></a></h1> | ||
<ol> | ||
<li>Add a <code>django.db.backends</code> logger at the level <code>DEBUG</code> in <code>settings.py</code>.</li> | ||
</ol> | ||
<div class="highlight"><pre><span></span><code><span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span> | ||
<span class="s1">'version'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> | ||
<span class="s1">'disable_existing_loggers'</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span> | ||
<span class="s1">'handlers'</span><span class="p">:</span> <span class="p">{</span> | ||
<span class="s1">'console'</span><span class="p">:</span> <span class="p">{</span> | ||
<span class="s1">'class'</span><span class="p">:</span> <span class="s1">'logging.StreamHandler'</span><span class="p">,</span> | ||
<span class="p">},</span> | ||
<span class="p">},</span> | ||
<span class="s1">'loggers'</span><span class="p">:</span> <span class="p">{</span> | ||
<span class="s1">'django.db.backends'</span><span class="p">:</span> <span class="p">{</span> | ||
<span class="s1">'handlers'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'console'</span><span class="p">],</span> | ||
<span class="s1">'level'</span><span class="p">:</span> <span class="s1">'DEBUG'</span><span class="p">,</span> | ||
<span class="p">},</span> | ||
<span class="p">},</span> | ||
<span class="p">}</span> | ||
</code></pre></div> | ||
|
||
<p>Tip: add debug log in your code to find where SQL is coming from. The logs</p> | ||
<h1>Using Django Debug Toolbar<a id="anchor-using-django-debug-toolbar"></a></h1> | ||
<p>The initial effort to install the toolbar is a bit higher than the other method. But when working on a website, this is a must have.</p> | ||
<ol> | ||
<li>Install it following the instructions <a href="https://django-debug-toolbar.readthedocs.io/en/latest/installation.html">here</a></li> | ||
<li>Open the page you want to inspect in your browser and check out the "SQL" section.</li> | ||
</ol> | ||
<p>TODO add pic</p> | ||
<h1>Using django-extensions and shell_plus<a id="anchor-django-extensions-shell-plus"></a></h1> | ||
<ol> | ||
<li><code>python -m pip install django-extensions</code></li> | ||
<li><code>./manage.py shell_plus --print-sql</code></li> | ||
<li>In the shell do a query, for example <code>User.objects.count()</code></li> | ||
</ol> | ||
<p>Official documentation: <a href="https://django-extensions.readthedocs.io/en/latest/shell_plus.html#sql-queries">here</a></p> | ||
<h1>Using django-extensions and runserver_plus<a id="anchor-django-extentions-runserver-plus"></a></h1> | ||
<ol> | ||
<li><code>python -m pip install django-extensions Werkzeug</code></li> | ||
<li><code>./manage.py runserver_plus --print-sql</code></li> | ||
<li>Do some HTTP requests and look in the logs for the SQL generated</li> | ||
<li>Killer feature: you can also pass the argument <code>--print-sql-location</code> and a stacktrace will be added to each SQL query to help you find from where it is coming.</li> | ||
</ol> | ||
<p>Those parameters are not officially documented, but do exist in the <a href="https://github.com/django-extensions/django-extensions/blob/81e79826fdbc127060539bcde0325d81c63e59c1/django_extensions/management/commands/runserver_plus.py#L193-L198">code</a>.</p> | ||
</span> | ||
|
||
<div class="meta__container--without-image"> | ||
<div class="row"> | ||
</div> | ||
</div> | ||
|
||
<br> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
</div> | ||
|
||
<footer class="copyrights"> | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="col-xs-12 col-sm-6"> | ||
Powered by <a href="https://github.com/getpelican/pelican">Pelican</a>. | ||
</div> | ||
<div class="col-xs-12 col-sm-6"> | ||
<div class="copyrights--right"> | ||
Made with <span class="glyphicon glyphicon-heart"></span> in Nantes. | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</footer> | ||
|
||
<script src="https://b0uh.github.io/theme/scripts/jquery.min.js"></script> | ||
<script src="https://b0uh.github.io/theme/scripts/underscore.min.js"></script> | ||
<script src="https://b0uh.github.io/theme/scripts/bootstrap.min.js"></script> | ||
<script src="https://b0uh.github.io/theme/scripts/main.min.js"></script> | ||
|
||
|
||
<script> | ||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); | ||
|
||
ga('create', 'UA-98369697-1', 'auto'); | ||
ga('send', 'pageview'); | ||
|
||
</script> | ||
|
||
<!-- Chiffre.io - Privacy-first analytics --> | ||
<script id="chiffre:analytics-config" type="application/json"> | ||
{ | ||
"publicKey": "pk.VvetZOQ0g5XwOL2W6hVvG7gFQTk3xdUMczDkqSCZUxE", | ||
"pushURL": "https://push.chiffre.io/event/ceJKfYgcLN6XkYn8" | ||
} | ||
</script> | ||
<script | ||
src="https://embed.chiffre.io/analytics.js" | ||
crossorigin="anonymous" | ||
async="" | ||
> | ||
</script> | ||
<noscript> | ||
<img | ||
src="https://push.chiffre.io/noscript/ceJKfYgcLN6XkYn8" | ||
alt="Chiffre.io anonymous visit counting for clients without JavaScript" | ||
crossorigin="anonymous" | ||
width="1px" | ||
height="1px" | ||
style="display:none" | ||
/> | ||
</noscript> | ||
|
||
|
||
</body> | ||
</html> |
Oops, something went wrong.