Skip to content

Commit

Permalink
Django: show me the sql
Browse files Browse the repository at this point in the history
  • Loading branch information
b0uh committed Feb 28, 2024
1 parent 4e85ce3 commit ce739e6
Show file tree
Hide file tree
Showing 15 changed files with 817 additions and 156 deletions.
2 changes: 2 additions & 0 deletions archives.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
<h1>Archives</h1>

<dl>
<dt>Wed 28 February 2024</dt>
<dd><a href="https://b0uh.github.io/django-show-me-the-sql.html">Django: show me the SQL</a></dd>
<dt>Wed 24 January 2024</dt>
<dd><a href="https://b0uh.github.io/list-of-python-web-frameworks.html">List of Python web frameworks</a></dd>
<dt>Wed 24 May 2023</dt>
Expand Down
2 changes: 1 addition & 1 deletion authors.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
<div class="container">
<h1>Authors on Thomas Loiret - Random thoughts</h1>
<ul>
<li><a href="https://b0uh.github.io/author/thomas-loiret.html">Thomas Loiret</a> (25)</li>
<li><a href="https://b0uh.github.io/author/thomas-loiret.html">Thomas Loiret</a> (26)</li>
</ul>
</div>

Expand Down
2 changes: 1 addition & 1 deletion categories.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
<h1>Categories on Thomas Loiret - Random thoughts</h1>
<ul>
<li><a href="https://b0uh.github.io/category/data.html">Data</a> (1)</li>
<li><a href="https://b0uh.github.io/category/django.html">django</a> (2)</li>
<li><a href="https://b0uh.github.io/category/django.html">django</a> (3)</li>
<li><a href="https://b0uh.github.io/category/management.html">Management</a> (1)</li>
<li><a href="https://b0uh.github.io/category/marketplace.html">Marketplace</a> (1)</li>
<li><a href="https://b0uh.github.io/category/performances.html">performances</a> (1)</li>
Expand Down
314 changes: 314 additions & 0 deletions django-show-me-the-sql.html
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> &nbsp; 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">&quot;gustave&quot;</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">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
<span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">},</span>
<span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;django.db.backends&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">],</span>
<span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</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>
Loading

0 comments on commit ce739e6

Please sign in to comment.