<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jonathan Sundqvist</title>
    <description>The latest articles on Forem by Jonathan Sundqvist (@jonathans).</description>
    <link>https://forem.com/jonathans</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F163437%2F6815b553-a14b-4660-857a-20f2926bea5f.jpeg</url>
      <title>Forem: Jonathan Sundqvist</title>
      <link>https://forem.com/jonathans</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jonathans"/>
    <language>en</language>
    <item>
      <title>How to configure github actions for a python package</title>
      <dc:creator>Jonathan Sundqvist</dc:creator>
      <pubDate>Sat, 14 Nov 2020 19:00:00 +0000</pubDate>
      <link>https://forem.com/jonathans/how-to-configure-github-actions-for-a-python-package-1019</link>
      <guid>https://forem.com/jonathans/how-to-configure-github-actions-for-a-python-package-1019</guid>
      <description>&lt;p&gt;This is what a build action for running a test matrix in github actions looks like in python. The yaml file is saved in &lt;code&gt;.github/workflows/&amp;lt;your_name&amp;gt;.yml&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Running unittests&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;3.6&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3.7&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3.8&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;django&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.2"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.0"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.1"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python ${{ matrix.python-version }}&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.python-version }}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
        &lt;span class="s"&gt;pip install -r requirements-tests.txt&lt;/span&gt;
        &lt;span class="s"&gt;if [-f requirements.txt]; then pip install -r requirements.txt; fi&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Linting&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flake8&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unittests&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;TOX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;py${{ matrix.python-version}}-django${{ matrix.django }}&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;tox -e $TOX_ENV&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the matrix we define the python versions and in this case also the django versions. &lt;code&gt;django&lt;/code&gt; in this case will be set as an environment variable.&lt;/p&gt;

&lt;p&gt;Further down I've set a TOX env to set exactly how I expect the tox environment variable to be set. So that is what I'm relying &lt;code&gt;tox&lt;/code&gt; to use in the end.&lt;/p&gt;

&lt;p&gt;The python package &lt;a href="https://github.com/ymyzk/tox-gh-actions" rel="noopener noreferrer"&gt;tox-gh-actions&lt;/a&gt; may help mapping the python versions with the tox versions. In this case I chose to do it directly with github actions to keep things simpler. One less dependency, one less worry so to speak.&lt;/p&gt;

&lt;p&gt;For the full documentation of all the things you can do with github actions there is the &lt;a href="https://docs.github.com/en/free-pro-team@latest/actions" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ci</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Creating a materialized view with SQL procedures</title>
      <dc:creator>Jonathan Sundqvist</dc:creator>
      <pubDate>Wed, 04 Dec 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/jonathans/creating-a-materialized-view-with-sql-procedures-2jil</link>
      <guid>https://forem.com/jonathans/creating-a-materialized-view-with-sql-procedures-2jil</guid>
      <description>&lt;p&gt;In newer versions of MySQL you can create materialized views directly without any SQL procedures. However I recently had to work with a database that used MySQL 5.6 and in that version it's not possible to create materialized views.&lt;/p&gt;

&lt;p&gt;To give some context of what the problem at hand was. There was a huge table with around 1.3 billion entries. In this table there were URLs that had the flag &lt;code&gt;green&lt;/code&gt; either set as true or false. The URLs are not unique. Depending on the date a URL could be flagged either as &lt;code&gt;green&lt;/code&gt; or not.&lt;/p&gt;

&lt;p&gt;What I needed was to get the distinct set of all URLs flagged as &lt;code&gt;green&lt;/code&gt;. If a URL got flagged as &lt;code&gt;green&lt;/code&gt; and then at a later date got unflagged as &lt;code&gt;green&lt;/code&gt; it should not show up in the final set of results.&lt;/p&gt;

&lt;p&gt;There isn't any particularly elegant way of creating a performant query to get that data. So I landed in creating a stored procedure to solve the problem.&lt;/p&gt;

&lt;p&gt;This stored procedure was then later used to backfill the table called &lt;code&gt;green_presenting&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's walk through what's actually happening in this stored procedure.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;delimiter&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;insert_urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="nb"&gt;VarChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="nb"&gt;TinyInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;datum&lt;/span&gt; &lt;span class="nb"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;hostwebsite&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;hostpartner&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;green_presenting&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;ELSE&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;website&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostpartner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostwebsite&lt;/span&gt; 
        &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;hostingproviders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;green_presenting&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`modified`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`green`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`hosted_by`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`hosted_by_id`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`hosted_by_website`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`partner`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`url`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;green&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostwebsite&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostpartner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;DUPLICATE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt;
        &lt;span class="n"&gt;modified&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt;
&lt;span class="k"&gt;delimiter&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before we start with the signature of the procedure. The very first we need to do is to change the delimiter, from using &lt;code&gt;;&lt;/code&gt; to &lt;code&gt;//&lt;/code&gt; that way it won't parse new &lt;code&gt;;&lt;/code&gt; as the end of a statement when we create the procedure.&lt;/p&gt;

&lt;p&gt;Let's continue with the signature of the procedure.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;insert_urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="nb"&gt;VarChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="nb"&gt;TinyInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;datum&lt;/span&gt; &lt;span class="nb"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The way to define paramaters is to use the keyword &lt;code&gt;IN&lt;/code&gt; followed by the parameter name and last the type of the parameter. You can also use the keyword &lt;code&gt;OUT&lt;/code&gt; or &lt;code&gt;INOUT&lt;/code&gt;. If you don't need to change the parameter in the procedure and have that changed propagated in the database there is no need to use anything else than &lt;code&gt;IN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A stored procedure always need to begin with &lt;code&gt;BEGIN&lt;/code&gt; and end with &lt;code&gt;END&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is how a new variable is created. Which you can then assign something to.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;ELSE&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above is the outline of what an IF statement looks like. Make sure not to forget &lt;code&gt;THEN&lt;/code&gt; :).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;website&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostpartner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostwebsite&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;hostingproviders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is where we assign the values to the variables we created earlier. It's done with &lt;code&gt;INTO&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;The above procedure just takes one entry. Since I also needed to backfill all data. I had to create a new procedure that iterates through all entries of the table.&lt;/p&gt;

&lt;p&gt;What's noteworthy here is how we create a cursor and loop through it. Otherwise it's pretty much self-explanatory.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;delimiter&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;backfill&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;gdatum&lt;/span&gt; &lt;span class="nb"&gt;DATETIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;ggreen&lt;/span&gt; &lt;span class="nb"&gt;TINYINT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;gid_hp&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;gurl&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="k"&gt;CURSOR&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;datum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;green&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;greencheck&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id_hp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="k"&gt;CONTINUE&lt;/span&gt; &lt;span class="k"&gt;HANDLER&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;FOUND&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;OPEN&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;read_loop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LOOP&lt;/span&gt;
    &lt;span class="k"&gt;FETCH&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;gdatum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ggreen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gid_hp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gurl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
      &lt;span class="n"&gt;LEAVE&lt;/span&gt; &lt;span class="n"&gt;read_loop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="n"&gt;insert_presenting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gurl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ggreen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gid_hp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gdatum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;LOOP&lt;/span&gt; &lt;span class="n"&gt;read_loop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;CLOSE&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt;
&lt;span class="k"&gt;delimiter&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The last missing bit would be to create a trigger, that calls the procedure &lt;code&gt;insert_urls&lt;/code&gt;. After that we more or less have everything what a materialized view usually does.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Remember Rust with Anki</title>
      <dc:creator>Jonathan Sundqvist</dc:creator>
      <pubDate>Fri, 21 Jun 2019 15:00:00 +0000</pubDate>
      <link>https://forem.com/jonathans/remember-rust-with-anki-58j8</link>
      <guid>https://forem.com/jonathans/remember-rust-with-anki-58j8</guid>
      <description>&lt;p&gt;I've read &lt;a href="https://www.amazon.com/Rust-Programming-Language-Steve-Klabnik/dp/1593278284" rel="noopener noreferrer"&gt;The Book&lt;/a&gt; once before, but it was a long time ago, and at some point I read an o'reilly book about rust too. At the time of reading those books. It felt like the language made sense. I would remember what I read, surely.&lt;/p&gt;

&lt;p&gt;A few months go by, and I feel like I want to do something in Rust, get deeper. So I sit down in front of my computer with a blank stare. What is the exact syntax of doing a for loop again in rust? Let alone how do you even make a generic struct that is trait bounded.&lt;/p&gt;

&lt;p&gt;Does it sound similar? Well, I decided I would do something about this, so I created an Anki deck which has 212 cards (updated 2019-06-21). The anki deck covers the rust book. The deck won't be that much of use if you haven't read the book. But I'd say it certainly helps you remember once you've read the book.&lt;/p&gt;

&lt;p&gt;If you've never heard of Anki; in short it's flash card program which uses &lt;a href="https://en.wikipedia.org/wiki/Spaced_repetition" rel="noopener noreferrer"&gt;spaced repetition&lt;/a&gt; to help you remember. So even if I step away from rust at some future point I will remember the syntax, and now that you've also got the deck so will you!&lt;/p&gt;

&lt;p&gt;You can download the &lt;a href="https://www.argpar.se/images/rust-anki.apkg" rel="noopener noreferrer"&gt;deck&lt;/a&gt; here. If you want to get a notification when I make any changes to the deck. Head over to my &lt;a href="https://www.argpar.se/posts/programming/remembering-rust-with-anki" rel="noopener noreferrer"&gt;own site&lt;/a&gt; and register your email, and I'll send you an update when I've added something new. &lt;/p&gt;

&lt;p&gt;If you've got any feedback send me a tweet, email or comment on &lt;a href="https://news.ycombinator.com/item?id=20243335" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt; :). I'll reply to any comments below too of course!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>anki</category>
    </item>
    <item>
      <title>Troubleshoot why crontab is not working</title>
      <dc:creator>Jonathan Sundqvist</dc:creator>
      <pubDate>Thu, 09 May 2019 15:00:00 +0000</pubDate>
      <link>https://forem.com/jonathans/troubleshoot-why-crontab-is-not-working-2gj4</link>
      <guid>https://forem.com/jonathans/troubleshoot-why-crontab-is-not-working-2gj4</guid>
      <description>&lt;p&gt;Crontab is a particularly finicky unix tool. It's not always the easiest to figure out why on earth your scheduled job is not running as it should.&lt;/p&gt;

&lt;p&gt;There are a number of things that could go wrong. The very first thing to do is of course to double check that the crontab syntax is doing what you expect it to do. &lt;a href="https://crontab.guru/" rel="noopener noreferrer"&gt;Crontab guru&lt;/a&gt; helps exactly with that.&lt;/p&gt;

&lt;p&gt;And as a reminder for what the stars and numbers signify.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# m   h   dom mon dow   username command&lt;/span&gt;
&lt;span class="c"&gt;# *   *   *   *   *     dokku    command to be executed&lt;/span&gt;
&lt;span class="c"&gt;# -   -   -   -   -&lt;/span&gt;
&lt;span class="c"&gt;# |   |   |   |   |&lt;/span&gt;
&lt;span class="c"&gt;# |   |   |   |   +----- day of week (0 - 6) (Sunday=0)&lt;/span&gt;
&lt;span class="c"&gt;# |   |   |   +------- month (1 - 12)&lt;/span&gt;
&lt;span class="c"&gt;# |   |   +--------- day of month (1 - 31)&lt;/span&gt;
&lt;span class="c"&gt;# |   +----------- hour (0 - 23)&lt;/span&gt;
&lt;span class="c"&gt;# +----------- min (0 - 59)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The crontab is located at &lt;code&gt;/etc/crontab&lt;/code&gt;, however &lt;strong&gt;don't&lt;/strong&gt; go and edit that file. Instead you can create a specific file related to the cronjob in &lt;code&gt;/etc/cron.d&lt;/code&gt;. Creating a specific file helps if you are running multiple applications on a host for instance. So you've edited the file and it's still not running.&lt;/p&gt;

&lt;p&gt;If you create a new file in &lt;code&gt;/etc/cron.d&lt;/code&gt;. Make sure that the file does &lt;strong&gt;not&lt;/strong&gt; contain any dot or else it won't run. It's also important that it has the correct permissions. The correct permissions for the file should be &lt;code&gt;-rw-r--r-- root root&lt;/code&gt;. Those permissions are the outcome of the following two commands.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

chown root:root yourcronfile
chmod 644 yourcronfile


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You might need to restart the cron service for it to pick up the changes you made. You can do that with &lt;code&gt;sudo service cron restart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can check the cron logs to make sure that the crontab is working correctly. The logs are by default located in &lt;code&gt;/var/log/syslog&lt;/code&gt;. And running the following grep command will get you all the cron logs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

grep cron /var/log/syslog


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Even if the job is logged there, any errors won't show up there. So it's helpful to log those separately. If you add the following snippet at the end of your crontab &lt;code&gt;&amp;gt;&amp;gt; /var/log/myjob.log 2&amp;gt;&amp;amp;1&lt;/code&gt;, it will do just that. You're bound to thank me later ;).&lt;/p&gt;

&lt;p&gt;Your cronjob will fail at some point. A service such as &lt;a href="https://deadmanssnitch.com/cases/89b251ba-1c4a-40a4-88e3-25cc65b908c2/snitches" rel="noopener noreferrer"&gt;Dead man's snitch&lt;/a&gt; will most certainly help you knowing &lt;em&gt;when&lt;/em&gt; it failed. The premise is that you'll send a request to their service and if no request has been sent in the last X minutes, it will notify you that your cronjob likely failed and you need to check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dokku interlude
&lt;/h2&gt;

&lt;p&gt;Having your crontab checked in with git is certainly helpful. If you're using dokku there is the helpful plugin &lt;code&gt;supply-config&lt;/code&gt; that does almost that. There is an &lt;a href="https://github.com/dokku-community/dokku-supply-config/pull/7" rel="noopener noreferrer"&gt;open PR&lt;/a&gt; that amends that gap. &lt;a href="http://dokku.viewdocs.io/dokku/deployment/one-off-processes/" rel="noopener noreferrer"&gt;Dokku documentation&lt;/a&gt; also have some helpful reminders on what to keep in mind when configuring a crontab.&lt;/p&gt;

&lt;p&gt;Have you stumbled upon any other ways that crontab could fail?&lt;/p&gt;

</description>
      <category>crontab</category>
      <category>devops</category>
      <category>dokku</category>
    </item>
    <item>
      <title>Deploying Django using Dokku</title>
      <dc:creator>Jonathan Sundqvist</dc:creator>
      <pubDate>Fri, 03 May 2019 10:04:12 +0000</pubDate>
      <link>https://forem.com/jonathans/deploying-django-using-dokku-18fj</link>
      <guid>https://forem.com/jonathans/deploying-django-using-dokku-18fj</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is also over on &lt;a href="https://www.argpar.se/posts/programming/deploy-django-using-dokku/" rel="noopener noreferrer"&gt;my personal blog&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  I want to see my site on the web!
&lt;/h2&gt;

&lt;p&gt;That's what I've thought many times, but the thought of deploying things often seems prohibitively complex (unless you go with heroku, which hides most of the complexities at the expense of your wallet). The world of operations is vast and it's sometimes difficult to get a grasp of where to start to achieve what you want; to deploy the site you built.&lt;/p&gt;

&lt;p&gt;So this guide should provide that foot in the door while simultanously feeling rewarding with achieving something in the very end, because spending hours without seeing any sort of result is no fun. Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Dokku
&lt;/h2&gt;

&lt;p&gt;Unless you already have a server where you can develop your project I would suggest that you give &lt;a href="https://www.scaleway.com/en/" rel="noopener noreferrer"&gt;scaleway&lt;/a&gt; a try. Once you've installed something like debian on your server. The very first thing to do is to configure &lt;a href="https://www.scaleway.com/en/docs/protect-server-fail2ban/" rel="noopener noreferrer"&gt;fail2ban&lt;/a&gt;. If you don't your server is bound to be hacked in no time, I learnt the hard way on a digital ocean droplet. You'd be surprised how often someone tries to login to your server.&lt;/p&gt;

&lt;p&gt;Now that you're ready to install Dokku follow the &lt;a href="http://dokku.viewdocs.io/dokku/getting-started/installation/#installing-the-latest-stable-version" rel="noopener noreferrer"&gt;official instructions&lt;/a&gt;. Once you've executed the bash command for the latest version, set up your &lt;em&gt;public&lt;/em&gt; SSH key and added an &lt;a href="https://my.bluehost.com/hosting/help/whats-an-a-record" rel="noopener noreferrer"&gt;A record&lt;/a&gt; for your server IP address you are ready to deploy your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Dokku for deployment
&lt;/h2&gt;

&lt;p&gt;If you don't yet have a Django project that you would like to deploy I would suggest that you use the following template which &lt;a href="https://gitlab.com/thiras/cookiecutter-docker-django" rel="noopener noreferrer"&gt;dockerizes django&lt;/a&gt;. It's a good starting point for any django project and already has sane defaults.&lt;/p&gt;

&lt;p&gt;Once you've executed the following commands you'll be able to run django locally. This is also what I'll be using as a base for deploying Django using Dokku.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

pip3 &lt;span class="nb"&gt;install &lt;/span&gt;cookiecutter
cookiecutter https://gitlab.com/thiras/cookiecutter-docker-django


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;SSH into your server and run the following commands&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# this is how you will refer to your app when using dokku&lt;/span&gt;
dokku apps:create your-django-app

&lt;span class="c"&gt;# install the postgres plugin to be able to use postgres with dokku&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dokku plugin:install https://github.com/dokku/dokku-postgres.git

&lt;span class="c"&gt;# creates a database for your app.&lt;/span&gt;
dokku postgres:create djangodb

&lt;span class="c"&gt;# link the above database to your app&lt;/span&gt;
dokku postgres:link djangodb your-django-app

&lt;span class="c"&gt;# configure which domain you'll be using for your app&lt;/span&gt;
&lt;span class="c"&gt;# I'd recommend using a fully qualified domain&lt;/span&gt;
domains:add your-django-app subdomain.yourdomain.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you're using the django app from the cookiecutter template you'll notice that it doesn't contain any &lt;code&gt;Procfile&lt;/code&gt;. Dokku does require a Procfile. So go ahead and add and commit a file named &lt;code&gt;Procfile&lt;/code&gt; containing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;web: gunicorn appname.wsgi:application --log-file&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You're now set and can try to deploy your django app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging deployment issues
&lt;/h2&gt;

&lt;p&gt;Dokku promises that you'll be able to deploy using git. Isn't that a treat. In the &lt;a href="http://dokku.viewdocs.io/dokku/deployment/application-deployment/#deploying-to-subdomains" rel="noopener noreferrer"&gt;dokku documentation&lt;/a&gt; it details how you should add the remote to git. These commands are&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# if you're using a subdomain&lt;/span&gt;
git remote add dokku dokku@yourdomain.com:subdomain

&lt;span class="c"&gt;# if you're deploying to the root domain&lt;/span&gt;
git remote add dokku dokku@dokku.me:dokku.me

git push dokku master


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: You fail to deploy. Because the host isn't recognized.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

fatal: &lt;span class="s1"&gt;'yourapp'&lt;/span&gt; does not appear to be a git repository
fatal: Could not &lt;span class="nb"&gt;read &lt;/span&gt;from remote repository.

Please make sure you have the correct access rights
and the repository exists.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: If you're facing this problem, perhaps because you're using a subdomain you can change the remote to contain the your public server IP instead. So the remote would look something like this instead &lt;code&gt;dokku@41.151.12.3:subdomain&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: It doesn't find a &lt;code&gt;Procfile&lt;/code&gt; even though you added one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: You might have file called &lt;code&gt;.dockerignore&lt;/code&gt;. If procfile is named there the container won't pick up your procfile. Removing that should fix that issue.&lt;/p&gt;

&lt;p&gt;We try to deploy again, and now it should actually deploy successfully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: While it successfully deploys the only thing you see is 400 Bad request. When you browse your site. How odd!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: In &lt;code&gt;settings.py&lt;/code&gt; you need to change &lt;code&gt;ALLOWED_HOSTS&lt;/code&gt; to your own domain. Once you've done this, you can now deploy your site again and that particular problem will go away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: You try to view the site. All static files such as CSS files returns 404. The site looks horrendous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: The development server serves static files for you. The gunicorn server does not. There is a management command &lt;code&gt;collectstatic&lt;/code&gt; that you need to run every time on deployment.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;app.json&lt;/code&gt;. There you can define commands that should run before deployment. You can read more about it in the &lt;a href="http://dokku.viewdocs.io/dokku/advanced-usage/deployment-tasks/#deployment-tasks" rel="noopener noreferrer"&gt;dokku documentation&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dokku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"predeploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python manage.py collectstatic --noinput"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will move your static files to the static folder you defined in &lt;a href="https://docs.djangoproject.com/en/2.2/howto/static-files/#managing-static-files-e-g-images-javascript-css" rel="noopener noreferrer"&gt;django settings&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you try to deploy again, thinking it is enough, it is not. These files need to be served as well. Nginx normally serves these files. So let's make that happen!&lt;/p&gt;

&lt;p&gt;Every deployment &lt;a href="http://dokku.viewdocs.io/dokku/configuration/nginx/#customizing-via-configuration-files-included-by-the-default-tem" rel="noopener noreferrer"&gt;Dokku generates&lt;/a&gt; an &lt;code&gt;nginx.conf&lt;/code&gt; file in &lt;code&gt;~home/dokku/appname&lt;/code&gt;. So we can't really edit that file. However if we take a look at the file it contains the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

include /home/dokku/appname/nginx.conf.d/&lt;span class="se"&gt;\*&lt;/span&gt;.conf&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So if we place any conf file in the folder &lt;code&gt;nginx.conf.d&lt;/code&gt; it should work. We'll place a file &lt;code&gt;static.conf&lt;/code&gt; containing the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

location /static &lt;span class="o"&gt;{&lt;/span&gt;
    autoindex on&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;alias&lt;/span&gt;   /home/dokku/appname/static&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However the above path is not where our static files are generated. They are generated inside our container. Also wouldn't it be nice if our &lt;code&gt;static.conf&lt;/code&gt; were in source control. You can accomplish that with the dokku plugin &lt;a href="https://github.com/dokku-community/dokku-supply-config" rel="noopener noreferrer"&gt;&lt;code&gt;supply-config&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In other words, we need a way to access the static files generated in our container. We can do that by mounting a volume where the static files are located.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

dokku docker-options:add your-django-app deploy &lt;span class="s2"&gt;"-v /home/dokku/appname/static:/app/appname/static"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The path after the colon is where your staticfiles are located after you run the command to collect your static files, and the path before the colon is the same path as in &lt;code&gt;static.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you deploy this time, even the static files should work. I'll let you in on a secret though. Instead of fiddling with nginx you could also use the django package &lt;a href="http://whitenoise.evans.io/en/stable/" rel="noopener noreferrer"&gt;whitenoise&lt;/a&gt; which is probably a more appropriate solution in this case.&lt;/p&gt;

&lt;p&gt;But if I told you directly you wouldn't have learnt about all the other Nginx configuration which might be useful for another day.&lt;/p&gt;

&lt;p&gt;As a complementary reading, I'd recommend checking out this guide on &lt;a href="https://www.stavros.io/posts/deploy-django-dokku/" rel="noopener noreferrer"&gt;deploying django using Dokku&lt;/a&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>devops</category>
      <category>dokku</category>
      <category>python</category>
    </item>
  </channel>
</rss>
