<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[GirlThatLovesToCode]]></title><description><![CDATA[I'm a self-taught-developer that is trying to encourage others to learn to code by blogging.
I'm writing about my experiences, CSS, JavaScript, Python...]]></description><link>https://girlthatlovestocode.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1628679925962/E5NDxWVI4.jpeg</url><title>GirlThatLovesToCode</title><link>https://girlthatlovestocode.com</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 09:21:10 GMT</lastBuildDate><atom:link href="https://girlthatlovestocode.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Fluent in Django: Get to know Django models better]]></title><description><![CDATA[Intro
Django is an MTV framework. Instead of MVC (Model, Views, Controller), it uses Model, Template, and View.
The View is a Python function that takes a Web request and returns a Web response (in MVC, this would be a Controller).
But the heart of y...]]></description><link>https://girlthatlovestocode.com/django-model</link><guid isPermaLink="true">https://girlthatlovestocode.com/django-model</guid><category><![CDATA[Django]]></category><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python projects]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Tue, 04 May 2021 09:13:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117209517/QzM7KgilP.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="intro">Intro</h2>
<p>Django is an MTV framework. Instead of MVC (Model, Views, Controller), it uses Model, Template, and View.
The View is a Python function that takes a Web request and returns a Web response (in MVC, this would be a Controller).
But the heart of your application is the <strong>Model</strong>.</p>
<p><strong>Django model</strong> is a class that subclasses <code>django.db.models.Model</code>. It contains the essential fields and behaviors of your data.</p>
<p>Usually, each model maps to a single database table and each attribute of the model represents a database field.</p>
<p>In the introductory Django tutorials, you usually create a <code>Model</code> with few basic fields, you mess with it in the <code>View</code> and show it in a template.</p>
<p>But <code>Model</code> is and can do so much more.
It is the single, definitive source of information about your data. 
That means that all the logic about your data should be located in the <code>Model</code> (not in <code>View</code> as too often can be seen).</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>You will need the basic knowledge of Django. If you don't feel comfortable with Django yet, try <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">this beginner-friendly tutorial</a>.</p>
<h2 id="initial-setup">Initial setup</h2>
<p>Start with setting up a new Django project:</p>
<pre><code class="lang-sh">$ mkdir django_models
$ <span class="hljs-built_in">cd</span> django_models
$ python3.9 -m venv venv
$ <span class="hljs-built_in">source</span> venv/bin/activate
(venv)$ pip install Django
(venv)$ django-admin startproject django_models .
</code></pre>
<p>Create a new app:</p>
<pre><code class="lang-sh">(venv)$ django-admin startapp tutorial
</code></pre>
<p>and register it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># django_models/settings.py</span>

INSTALLED_APPS = [
    <span class="hljs-string">'django.contrib.admin'</span>,
    <span class="hljs-string">'django.contrib.auth'</span>,
    <span class="hljs-string">'django.contrib.contenttypes'</span>,
    <span class="hljs-string">'django.contrib.sessions'</span>,
    <span class="hljs-string">'django.contrib.messages'</span>,
    <span class="hljs-string">'django.contrib.staticfiles'</span>,
    <span class="hljs-string">'tutorial'</span>,
]
</code></pre>
<p>Now for the <code>Model</code>. We will be working on a <code>Model</code> for a marathon app. 
Our <code>Model</code> will be called <code>Runner</code> and at the beginning, it will only have 3 fields. As our business logic will progress, so will our <code>Model</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
</code></pre>
<p>For now, each runner will only have 3 fields:</p>
<ul>
<li><code>name</code> is basic <code>CharField</code> with max of 50 characters (<code>max_length</code> is mandatory parameter for a <code>CharField</code>)</li>
<li><code>last_name</code> is basic <code>CharField</code> with a max of 50 characters</li>
<li><code>email</code> is an <code>EmailField</code> - that's a <code>CharField</code> that checks that the value is a valid email address using <a target="_blank" href="https://docs.djangoproject.com/en/3.2/ref/validators/#emailvalidator">EmailValidator</a>.</li>
</ul>
<p>Our model doesn't include any additional logic.</p>
<p>Create and run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<blockquote>
<p>If you got lost during the initial setup, I encourage you to go <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">back to basics</a>.</p>
</blockquote>
<p>We won't be dealing with templates or views, so this concludes the basic setup.
However, we need to be able to see the data somewhere, so include the Runner model in the admin panel.</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/admin.py</span>

<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Runner


admin.site.register(Runner)
</code></pre>
<p>Create a superuser and run the server:</p>
<pre><code class="lang-sh">(venv)$ python manage.py createsuperuser
(venv)$ python manage.py runserver
</code></pre>
<h2 id="uuid">UUID</h2>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">Universally unique identifier</a>  is a 128-bit number, usually represented as 32 hexadecimal characters separated by four hyphens.
The probability that a UUID will be duplicated is not zero, but it is close enough to zero to be negligible.</p>
<p>ID that Django uses out-of-the-box is incremented sequentially. That means that the 5th registered user has an id 5 and the 6th one has id 6.
So, if I register and figure out that my id is 17, I know there were 16 people registered before me and I can try to get to their data by using their id. That makes your application very vulnerable.</p>
<p>That's where UUID comes in handy. UUID key is randomly generated, so it doesn't carry any information as of how many people are registered to the page or what their id might be.</p>
<p>Django has a special field, called <a target="_blank" href="https://docs.djangoproject.com/en/3.2/ref/models/fields/">UUIDField</a> for storing UUIDs.</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>

<span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
</code></pre>
<p>You added a new id field -- <code>UUIDField</code> and you made that field <code>PRIMARY_KEY</code> for the <code>Runner</code> table.
<code>UUID</code> can be built in <a target="_blank" href="https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions">5 different ways</a>, but you'll probably want a unique and randomly generated version - version 4.
You set it as a default with <code>default=uuid.uuid4</code>.
You also don't want anyone to change that field, so you've set <code>editable</code> to <code>False</code>.</p>
<p>Run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<p>Now login with your superuser and add a test runner in the admin and see how it looks on the list of objects - that weird number in the name of the object is a <code>UUID</code>. If you add another runner, the string will be different.</p>
<p>Before adding the uuid the name of the object looked like that:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116910304/n5ME9-1jL.png" alt="before_uuid.png" /></p>
<p>And after adding the uuid, it looks like that:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116791511/JSpB9sTBa.png" alt="uuid.png" /></p>
<blockquote>
<p>If you added any object before you've added the UUID, your database will fall apart. Before adding a new primary key, delete all the test object you added.</p>
<p>If you need to add a new primary key in production, things tend to get bloody - so don't do that. Think ahead and start with adding <code>UUID</code> at the beginning of the project.</p>
</blockquote>
<h2 id="choices">Choices</h2>
<p>Imagine this amazing marathon runner that last year won the Berlin marathon. Will you squish him between someone who's there just for fun and someone who decided 6 months ago that he'll run the marathon? Of course, not.
Marathon start is divided into zones - the faster you are, the closer to the start line you are. If you don't have any previous results, you're in the 5th zone. And if all you do is eat, sleep and run, you're in the first zone.</p>
<p>It would be useful if we'd have a zone saved in our database for each of the runners. 
We could use an integer field, but then the user would be able to enter any number, even 100. We need to limit the entries to the 5 choices they have.</p>
<p>Since Django 3.0, there is a Choices class that extends <a target="_blank" href="https://docs.python.org/3/library/enum.html">Python’s Enum types</a> with extra constraints and functionality.</p>
<blockquote>
<p><strong>Python Enumeration type</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116819472/86ou5w1ap.png" alt="enumerated_type.png" /></p>
<p>An enumeration is a set of symbolic names (members) bound to unique, constant values.</p>
<p>Enumeration can be iterated over. Members are immutable and can be compared.
They are constants, so the names should be uppercase.</p>
</blockquote>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>

<span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-comment"># this is new:</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>) <span class="hljs-comment"># this is new</span>
</code></pre>
<p>We created a Choice class (an enumeration) called <code>Zone</code> that has 5 members. 
The first part (eg. <code>ZONE_1</code>) is the name of the enumeration member. The second part (eg. <code>1</code>) is the actual value.
The third part (eg. <code>'Less than 3.10'</code>) is a human-readable name, label. This is what you'll see in the admin. </p>
<p>The Choices class has two subclasses - <code>IntegerChoices</code> and <code>TextChoices</code>. Since we're only interested in the numbers of the zones, we used <code>IntegerChoices</code> (it doesn't matter that constant names and labels are string, you choose the type based on the values).</p>
<p>Now we need to connect those choices to a database field. Because we provided <code>IntegerChoices</code>, the field has to be one of the integer fields.
Because we know there'll always be only a handful of zone possibilities, we chose <code>PositiveSmallIntegerField</code>. 
We connected the Choice class to the field with <code>choices=Zone.choices</code>.
We selected the default value for the field and here you can see how we access one of the members (<code>Zone.ZONE_5</code>).
The new addition is also <code>help_text</code> - this will show either in form or in the admin to help the user know what data they need to enter.</p>
<p>Run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<p>You should be logged in from before, open the form to add another runner, and see what changed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116856823/u5DQ0zZyk.png" alt="start_zone_added.png" /></p>
<p>Here you can see the help text you provided and the human-readable labels from the <code>Zone</code> class.</p>
<h2 id="str">__str__()</h2>
<p>If you open http://127.0.0.1:8000/admin/tutorial/runner/, you'll see the list of the runners you've added (you should at least have one), but you have no idea about the runners. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116956545/96wLDu298.png" alt="before_str.png" /></p>
<p>You can just see an object with some id. If you'd want to edit someone, you'd need to open each of the objects and find the one with the right name and surname.
The method, that takes care of how the objects look when presented in a string (like on the list of runners) is the <code>__str__</code> method.</p>
<p><code>__str__</code> is a Python method that returns a string representation of any object. This is what Django uses to display model instances as a plain string.</p>
<blockquote>
<p>Django documentation says:</p>
<p>"You’ll always want to define this method; the default isn’t very helpful at all."</p>
</blockquote>
<p>Let's obey Django creators and change the representation of the object to something more readable:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>)

    <span class="hljs-comment"># this is new:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'%s %s'</span> % (self.name, self.last_name)
</code></pre>
<p>Here you're using Python string formatting to create a string out of two variables - name and last name.</p>
<blockquote>
<p>You don't need to use only variables to create the object's string representation.
If you want the runners presented in a last_name, name - zone form, you can do this:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
  <span class="hljs-keyword">return</span> <span class="hljs-string">'%s, %s - %s'</span> % (self.last_name, self.name, self.start_zone)
</code></pre>
</blockquote>
<p>Refresh the runners' admin page, and now it's way easier to navigate through all the runners:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116969978/qfsrqotjB.png" alt="str.png" /></p>
<blockquote>
<p><strong>Why don't I have to run the migrations for this to work?</strong></p>
<p>Migrations are Django's way to propagate changes you make to your models to your database schema.
So you need to run the migrations only when the changes you made, impact your database.
Here you only changed the string representation of an object and that doesn't impact it, so there is no need to run the migration.</p>
</blockquote>
<h2 id="meta">Meta</h2>
<p>As I mentioned at the beginning of this post, Django <code>Model</code> is more than just a class with a bunch of fields.
Any additional business logic has a place in the model. </p>
<p>But anything that's not a field, is considered metadata and has a special place inside the model - inside the inner <code>Meta</code> class.</p>
<p><code>Meta</code> class is optional, but inside it, you can change the ordering, set the verbose name, add permissions...</p>
<h3 id="verbose-names">verbose names</h3>
<p>I used a simple name for the class, but maybe I'd like to use a more descriptive name for the users.</p>
<p>Also, if you noticed, in the Django admin, your class with a singular name (Runner) is transformed to plural (Runners) - what if the plural is different than just added "s" (mouse -&gt; mice)?</p>
<p>You can set both, singular and plural human-readable names.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>)

    <span class="hljs-comment"># this is new:</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        verbose_name = <span class="hljs-string">"Runner 42k"</span>
        verbose_name_plural = <span class="hljs-string">"Runners 42k"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'%s %s'</span> % (self.name, self.last_name)
</code></pre>
<p>You've set the <code>verbose_name</code> and <code>verbose_name_plural</code> to something different in the <code>Meta</code> class.</p>
<p>If you refresh the admin, you'll see that both changed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116984046/ggQ_9gHd5.png" alt="verbose_name.png" /></p>
<h3 id="ordering">ordering</h3>
<p>Inside class <code>Meta</code>, you can select the default ordering of the objects when the list of objects will be retained.</p>
<p>There's a great chance, that whatever you'll do with the Runner objects, you'll care in which zone they are.
So it would be a good idea to order them by the zone.</p>
<p>To be able to see that they are sorted by zone, do 2 things:</p>
<ol>
<li>add 4 more runners from different zones in no particular order.</li>
<li>Change the <code>__str__</code> method, so it will also show the zone</li>
</ol>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>)

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        verbose_name = <span class="hljs-string">"Runner 42k"</span>
        verbose_name_plural = <span class="hljs-string">"Runners 42k"</span>
        ordering = [<span class="hljs-string">"start_zone"</span>] <span class="hljs-comment"># this is new</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'%s %s %s'</span> % (self.name, self.last_name, self.start_zone) <span class="hljs-comment"># we added start_zone to the string</span>
</code></pre>
<p>Before the order was set:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620116999369/YYTg9sqs7.png" alt="before_order.png" /></p>
<p>After <code>ordering = ["start_zone"]</code> was added:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117017908/CtFmwkYQT.png" alt="after_order.png" /></p>
<blockquote>
<p>It is possible to order by more than one criterion. You could sort it first by start_zone and then alphabetically by name. You could also sort it in reversed order, so the zone 5 runners are at the top (you add <code>-</code> inside the string before the name to reverse it).</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
  ordering = [<span class="hljs-string">"-start_zone"</span>, <span class="hljs-string">"name"</span>]
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117034465/1aQTJUZ42.png" alt="different_order.png" /></p>
</blockquote>
<h3 id="constraints">constraints</h3>
<h4 id="checkconstraint">CheckConstraint</h4>
<p>Because long runs for youngsters are advised against, the organizer permits only runners that will be of age this calendar year.
You have special <a target="_blank" href="https://docs.djangoproject.com/en/3.2/ref/models/constraints/">constraints classes</a> for that purpose.</p>
<p>You need to add a constraint that won't allow people under 18 (or with their 18th birthday coming this year) to register.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>)
    year_born = models.PositiveSmallIntegerField(default=<span class="hljs-number">1990</span>) <span class="hljs-comment"># new field added</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        verbose_name = <span class="hljs-string">"Runner 42k"</span>
        verbose_name_plural = <span class="hljs-string">"Runners 42k"</span>
        ordering = [<span class="hljs-string">"-start_zone"</span>, <span class="hljs-string">"name"</span>]
        constraints = [ <span class="hljs-comment"># constraints added</span>
            models.CheckConstraint(check=models.Q(year_born__lte=datetime.date.today().year<span class="hljs-number">-18</span>), name=<span class="hljs-string">'will_be_of_age'</span>),
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'%s %s %s'</span> % (self.name, self.last_name, self.start_zone)
</code></pre>
<p>To be able to check if the birth year is valid, you need to add the field <code>year_born</code> to your <code>Runner</code> model.</p>
<p>Inside class <code>Meta</code>, you add constraints in a form of a list. Since you're <strong>checking</strong> if a person is old enough, you're using <code>CheckConstraint</code>.</p>
<p><code>CheckConstraint</code> consist of two mandatory parts:</p>
<ul>
<li>check - A <a target="_blank" href="https://docs.djangoproject.com/en/3.2/ref/models/querysets/#q-objects">Q object</a> or boolean expression that specifies the check you want the constraint to enforce.</li>
<li>name - An unique name for the constraint</li>
</ul>
<blockquote>
<p><code>Q</code> encapsulates filters as objects that can then be combined logically (using <code>&amp;</code> and <code>|</code>), thus making it possible to use conditions in database-related operations.</p>
</blockquote>
<p>The check in our case checks if the year entered in the field <code>year_born</code> is less or equal(<code>year_born__lte=</code>) to today's year minus 18 years(<code>datetime.date.today().year-18</code>).</p>
<p>Run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<p>Try to add a runner with <code>year_born</code> 2010. You'll get an integrity error:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117051678/QgNRHxzHx.png" alt="age_constraint_error.png" /></p>
<h4 id="uniqueconstraint">UniqueConstraint</h4>
<p>Let's add another constraint. Because there have been some mixups in previous runs, the organizer wants to forbid 2 persons with the same name start in the same zone.</p>
<p>You need to add the constraint that will prevent adding another runner with the same name, surname, and start_zone.
A person with the same name can start in another zone.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>)
    year_born = models.PositiveSmallIntegerField(default=<span class="hljs-number">1990</span>)

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        verbose_name = <span class="hljs-string">"Runner 42k"</span>
        verbose_name_plural = <span class="hljs-string">"Runners 42k"</span>
        ordering = [<span class="hljs-string">"-start_zone"</span>, <span class="hljs-string">"name"</span>]
        constraints = [
            models.CheckConstraint(check=models.Q(year_born__lte=datetime.date.today().year<span class="hljs-number">-18</span>), name=<span class="hljs-string">'will_be_of_age'</span>),
            models.UniqueConstraint(fields=[<span class="hljs-string">'name'</span>, <span class="hljs-string">'last_name'</span>, <span class="hljs-string">'start_zone'</span>], name=<span class="hljs-string">'unique_person'</span>) <span class="hljs-comment"># new constraint added</span>
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'%s %s %s'</span> % (self.name, self.last_name, self.start_zone)
</code></pre>
<p>Since you want a set of fields to be <em>unique</em>, you're using <code>UniqueConstraint</code>. You have to specify which combination of fields you want to be unique in a list (in our case <code>fields=['name', 'last_name', 'start_zone']</code>), and as in the previous case, you have to set a unique name for the constraint.</p>
<p>Try to add another person with the same name, surname, and in the same zone.
This is what you'll get:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117065077/Xw2tkPn2m.png" alt="unique_error.png" /></p>
<p>If you change any of those fields, the record will be added to DB without any problem.</p>
<blockquote>
<p><strong>Why do I get different errors?</strong></p>
<p>You might have noticed that in the case of a unique constraint, there was a notice inside Django admin, and in the case of age constraint, you've been redirected to an error page.</p>
<p>That's because, in <code>UniqueConstraints</code>, you were comparing fields that were already there, so the error happened prior to saving the record to the database. But in the case of <code>CheckConstraints</code>, you were dealing with the database (<code>Q()</code> represents an SQL condition).</p>
</blockquote>
<h2 id="change-the-save-method">change the save method</h2>
<p>There will be times when you'll want to overwrite the predefined save method. Maybe you'll want to add an additional field (eg. creation date), change the format (eg. string to date), or prevent a certain type of data.</p>
<p>If you want to start running in the start zone that is not the slowest (nr. 5 in our case), you have to have a previous record to prove that you can run so fast and you won't obstruct other runners.
We'll add a field for entering the previous record and in the custom save method check if the field has value.
If not, the runner will automatically be assigned to zone nr. 5, regardless of what they chose.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> uuid
<span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Runner</span>(<span class="hljs-params">models.Model</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span>(<span class="hljs-params">models.IntegerChoices</span>):</span>
        ZONE_1 = <span class="hljs-number">1</span>, <span class="hljs-string">'Less than 3.10'</span>
        ZONE_2 = <span class="hljs-number">2</span>, <span class="hljs-string">'Less than 3.25'</span>
        ZONE_3 = <span class="hljs-number">3</span>, <span class="hljs-string">'Less than 3.45'</span>
        ZONE_4 = <span class="hljs-number">4</span>, <span class="hljs-string">'Less than 4 hours'</span>
        ZONE_5 = <span class="hljs-number">5</span>, <span class="hljs-string">'More than 4 hours'</span>

    name = models.CharField(max_length=<span class="hljs-number">50</span>)
    last_name = models.CharField(max_length=<span class="hljs-number">50</span>)
    email = models.EmailField()
    id = models.UUIDField(primary_key=<span class="hljs-literal">True</span>, default=uuid.uuid4, editable=<span class="hljs-literal">False</span>)
    start_zone = models.PositiveSmallIntegerField(choices=Zone.choices, default=Zone.ZONE_5, help_text=<span class="hljs-string">"What was your best time on the marathon in last 2 years?"</span>)
    year_born = models.PositiveSmallIntegerField(default=<span class="hljs-number">1990</span>)
    best_run_time = models.DurationField(default=datetime.timedelta(hours=<span class="hljs-number">4</span>)) <span class="hljs-comment"># new field added</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        verbose_name = <span class="hljs-string">"Runner 42k"</span>
        verbose_name_plural = <span class="hljs-string">"Runners 42k"</span>
        ordering = [<span class="hljs-string">"-start_zone"</span>, <span class="hljs-string">"name"</span>]
        constraints = [
            models.CheckConstraint(check=models.Q(year_born__lte=datetime.date.today().year<span class="hljs-number">-18</span>), name=<span class="hljs-string">'will_be_of_age'</span>),
            models.UniqueConstraint(fields=[<span class="hljs-string">'name'</span>, <span class="hljs-string">'last_name'</span>, <span class="hljs-string">'start_zone'</span>], name=<span class="hljs-string">'unique_person'</span>)
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'%s %s %s'</span> % (self.name, self.last_name, self.start_zone)

    <span class="hljs-comment"># this is new:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">save</span>(<span class="hljs-params">self, *args, **kwargs</span>):</span>

        <span class="hljs-keyword">if</span> self.best_run_time &gt;= datetime.timedelta(hours=<span class="hljs-number">4</span>):
            self.start_zone = self.Zone.ZONE_5

        super(Runner, self).save(*args, **kwargs)
</code></pre>
<p>You added a new field, <code>best_run_time</code>. Here we're also introducing a new type of field - <code>DurationField</code>.</p>
<p><code>DurationField</code> is a field for storing periods of time - modeled in Python by <code>timedelta</code>.
In Django admin, it's shown as an empty field, which is a little impractical, so we provided the default value, so you can edit it easily.
We've automatically set it to 4 hours with Python's <code>timedelta</code> class.</p>
<blockquote>
<p>You <strong>can't</strong> compare instances <code>DurationField</code> to instances of <code>DateTimeField</code> (the only exception is if using PostgreSQL). </p>
</blockquote>
<p>At the bottom, you've overwritten the <code>save</code> method. You check if the <code>best_run_time</code> is more than or equal to 4 hours (<code>datetime.timedelta(hours=4)</code>) and if it is, you automatically set the <code>start_zone</code> to zone 5 (<code>self.start_zone = self.Zone.ZONE_5</code>).</p>
<p>Run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<p>And try to add a runner with zone selected to something less than 5. Leave the <code>best_run_time</code> as it is (4 hours).
The runner will save without any problems, but if you check the added runner, you'll see that their start zone changed to "More than 4 hours".</p>
<p>Prior to saving:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117088559/VLf95nCwT.png" alt="save_method_prior_save.png" /></p>
<p>After saving:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1620117100846/7xC4WNN4m.png" alt="save_after_save.png" /></p>
<p>As you can see, the start zone has changed. If Charlie's <code>best_run_time</code> would be less than 4 hours, his selected start zone would be left as he selected it.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Django models are very powerful and they hide much more than you got to know here.</p>
<p>Nevertheless, you got to know a lot about Django models:</p>
<ul>
<li>less known fields<ul>
<li><code>EmailField</code></li>
<li><code>UUIDField</code></li>
<li><code>DurationField</code></li>
</ul>
</li>
<li>how to add Choices field with the newest Django practice, using enumerators</li>
<li>how to change the method for the string representation of the object</li>
<li>how to work with the model's metadata:<ul>
<li>verbose names</li>
<li>ordering</li>
<li>constraints</li>
</ul>
</li>
<li>how to overwrite the default <code>save()</code> method</li>
</ul>
<p>Needless to say, some of the use cases are inappropriate for production. You can't prohibit a runner with the same name from running or automatically assign a runner who forgot to enter their best time to the slowest zone without notifying them.
However, those cases are real-life enough to give you a fair idea of what you might use them for in your real-life application.</p>
<p><sub>Image by wal_172619 from Pixabay</sub></p>
]]></content:encoded></item><item><title><![CDATA[Fluent in Django: 10+ Django template filters you should know]]></title><description><![CDATA[Prerequisites
You will need the basic knowledge of Django. If you don't feel comfortable with Django yet, try this beginner-friendly tutorial.
Django template filters
While tags lives between curly braces and a percent ({% tag %}), variables live bet...]]></description><link>https://girlthatlovestocode.com/django-template-filters</link><guid isPermaLink="true">https://girlthatlovestocode.com/django-template-filters</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Django]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 28 Apr 2021 07:38:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594775095/VXeZLf8lC.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="prerequisites">Prerequisites</h2>
<p>You will need the basic knowledge of Django. If you don't feel comfortable with Django yet, try <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">this beginner-friendly tutorial</a>.</p>
<h2 id="django-template-filters">Django template filters</h2>
<p>While <a target="_blank" href="https://girlthatlovestocode.com/django-template-tags">tags</a> lives between curly braces and a percent (<code>{% tag %}</code>), variables live between double curly braces (<code>{{ variable }}</code>).
You can influence the variable by using filters.</p>
<p>Filters are functions registered to the template engine that takes a value as input and return transformed value.</p>
<blockquote>
<p>IF YOU'RE CURIOUS</p>
<p>All the default filter functions are written in a file <code>defaultfilters.py</code>. This is how a wordcount filter looks like:</p>
<pre><code class="lang-python"><span class="hljs-meta">@register.filter(is_safe=False)</span>
<span class="hljs-meta">@stringfilter</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wordcount</span>(<span class="hljs-params">value</span>):</span>
   <span class="hljs-string">"""Return the number of words."""</span>
   <span class="hljs-keyword">return</span> len(value.split())
</code></pre>
</blockquote>
<p>A filter is separated from a variable with a pipe <code>{{ variable|filter }}</code>.
It is possible to use more than one filter on the variable - you just add another pipe and specify the filter (<code>{{ variable|filter1|filter2 }}</code>).</p>
<h2 id="initial-setup">Initial setup</h2>
<blockquote>
<p>We will work on a similar project as for the <a target="_blank" href="https://girlthatlovestocode.com/django-template-tags">Django template tags</a>.
If you did that tutorial, feel free to skip the initial setup and work on the project you created based on the Django template tags tutorial.
We will work on a template with a different name, so feel free to join the initial setup from <a class="post-section-overview" href="#joinback">where we're changing the <code>tutorial/urls.py</code></a>.
If you didn't you'll be easily able to follow, just go through the initial setup first.</p>
</blockquote>
<p>Start with setting up a new Django project:</p>
<pre><code class="lang-sh">$ mkdir django_template_tutorial
$ <span class="hljs-built_in">cd</span> django_template_tutorial
$ python3.9 -m venv venv
$ <span class="hljs-built_in">source</span> venv/bin/activate
(venv)$ pip install Django
(venv)$ django-admin startproject django_template_filters .
</code></pre>
<p>Create a new app:</p>
<pre><code class="lang-sh">(venv)$ django-admin startapp tutorial
```__

and register it:
```python
<span class="hljs-comment"># django_templates/settings.py</span>

INSTALLED_APPS = [
    <span class="hljs-string">'django.contrib.admin'</span>,
    <span class="hljs-string">'django.contrib.auth'</span>,
    <span class="hljs-string">'django.contrib.contenttypes'</span>,
    <span class="hljs-string">'django.contrib.sessions'</span>,
    <span class="hljs-string">'django.contrib.messages'</span>,
    <span class="hljs-string">'django.contrib.staticfiles'</span>,
    <span class="hljs-string">'tutorial'</span>,
]
</code></pre>
<p>Create a model called <code>Expense</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expense</span>(<span class="hljs-params">models.Model</span>):</span>
    datetime = models.DateTimeField()
    name = models.CharField(max_length=<span class="hljs-number">100</span>)
    amount = models.FloatField()
</code></pre>
<p>Create and run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<blockquote>
<p>If you got lost during the initial setup, I encourage you to go <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">back to basics</a>.</p>
</blockquote>
<p>Create a folder called <code>templates</code> inside the <code>tutorial</code> folder and inside it, another folder, again called <code>tutorial</code>.
Inside said structure, create a template called <code>filtered_expenses.html</code>:</p>
<pre><code><span class="hljs-selector-tag">django_templates</span>
    └── <span class="hljs-selector-tag">tutorial</span>
        └── <span class="hljs-selector-tag">templates</span>
            └── <span class="hljs-selector-tag">tutorial</span>
                └── <span class="hljs-selector-tag">filtered_expenses</span><span class="hljs-selector-class">.html</span>
</code></pre><p>Create a basic html for your filters:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Expenses<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mt-5"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- we'll add the code for filters here when we finnish the setup--&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Everything we're going to add will be added between the <code>&lt;div class="container mt-5"&gt;</code> and <code>&lt;/div&gt;</code>.</p>
<p>Now we need to create an url where our template will be shown.</p>
<p>Open <code>django_templates/urls.py</code> and include tutorial's urls in it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># django_template_filters/urls.py</span>

<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include  <span class="hljs-comment"># this is new</span>


urlpatterns = [
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
    path(<span class="hljs-string">''</span>, include(<span class="hljs-string">'tutorial.urls'</span>)), <span class="hljs-comment"># this is new</span>
]
</code></pre>
<p></p><p id="joinback">We haven't created <code>tutorial/urls.py</code> yet.</p> Create the file and define just the root url:<p></p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/urls.py</span>

<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> tutorial <span class="hljs-keyword">import</span> views

urlpatterns = [
    path(<span class="hljs-string">''</span>, views.filter_expenses_list),
]
</code></pre>
<p>And the last thing is to create a view called <code>filter_expenses_list</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/views.py</span>

<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> tutorial.models <span class="hljs-keyword">import</span> Expense


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">filter_expenses_list</span>(<span class="hljs-params">request</span>):</span>
    filter_expenses_list = Expense.objects.order_by(<span class="hljs-string">'-datetime'</span>)

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'tutorial/filtered_expenses.html'</span>, {<span class="hljs-string">'expenses'</span>: filter_expenses_list})
</code></pre>
<p>The last thing to do is to add some expenses via admin so we will be able to work with something.</p>
<p>Register the <code>Expense</code> model on the admin site in the <code>admin.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/admin.py</span>

<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Expense

admin.site.register(Expense)
</code></pre>
<p>Create the superuser:</p>
<pre><code class="lang-sh">(venv)$ python manage.py createsuperuser
</code></pre>
<p>Start the server:</p>
<pre><code class="lang-sh">(venv)$ python manage.py runserver
</code></pre>
<p>Open http://127.0.0.1:8000/admin/, log in with the superuser you created, and add 5 expenses.</p>
<p>This was a long setup, right?
Since this is an advanced tutorial, I didn't explain the setting project up. If you didn't understand something, feel free to consult the <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">beginners tutorial</a>.</p>
<p><strong>Let's get to work</strong></p>
<h2 id="change-case">Change case</h2>
<p>Filters allow you to change the case on the word - word can be all caps, all lowercase, you can capitalize the first letter...
To see the effect of each of those filters, open your <a target="_blank" href="http://127.0.0.1:8000/admin/">admin panel</a> and make the expense names varied - one all lowercase, one starting with a number, one with multiple words...</p>
<p>Edit your html file, so it will list the expenses in a table:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p>We will be adding different filters to <code>{{ expense.name }}</code> part.</p>
<h3 id="title">title</h3>
<p><code>title</code> converts a string into a title case by making words start with an uppercase character and the remaining characters lowercase.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name|title }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span> <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594864533/Jvz5fVDvr.png" alt="title.png" /></p>
<h3 id="capfirst">capfirst</h3>
<p><code>capfirst</code> capitalizes the first character of the value. If the first character is not a letter, this filter has no effect.
Switch <code>title</code> for <code>capfirst</code> filter to the <code>{{ expense.name }}</code>.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name|capfirst }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span> <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594880242/8Q8DSDfII.png" alt="capfirst.png" /></p>
<h3 id="lower">lower</h3>
<p><code>lower</code> converts a string into all lowercase. Switch the <code>capfirst</code> for a <code>lower</code>.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name|lower }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span> <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594902478/xMd7uXAGB.png" alt="lower.png" /></p>
<h3 id="upper">upper</h3>
<p><code>upper</code> converts a string into all uppercase. Switch the <code>lower</code> for an <code>upper</code>.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name|upper }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span> <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594916444/TB89mKJwi.png" alt="upper.png" /></p>
<h2 id="date">date</h2>
<p>Let's say we're only interested to show the date of the expense, not the time.
Edit the <code>{{ expense.datetime }}</code> part in the template:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime|date:"jS F Y" }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span> <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p><code>|date</code> is usually followed by a colon and a desired format in the string. If not, <code>DATE_FORMAT</code> is used (you can set it in <code>settings.py</code>).
In this case, we displayed the date as:</p>
<ul>
<li>days: <code>jS</code> - day of the month without the leading zero (<code>j</code>) + English ordinal suffix for the day of the month (<code>S</code>)</li>
<li>month: <code>F</code> - the full-textual name of the month</li>
<li>year: <code>Y</code> - 4 digits year</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594931317/_sGbpZTeI.png" alt="date_format.png" /></p>
<blockquote>
<p>You can check all the possible date formats in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#date">documentation</a>.</p>
<p>In the same way, you set the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#time">time</a> format. You can also combine it to show both.</p>
</blockquote>
<h2 id="timesince">timesince</h2>
<p><code>timesince</code> formats a date as the time since the date in the variable. Let's provide a user with a notice as to how much time has passed since their last expense.</p>
<p>Add this code to your html file:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-success"</span>&gt;</span>
    It's been {{ expenses.0.datetime|timesince }} since your last expense.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>timesince</code> shows: years, months, weeks, days, hours, minutes.
However, the time that passed is not always exact (the difference between 2020-02-02 and 2021-04-21 is "1 year, 2 months").</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594944796/tv-CR6jsG.png" alt="timesince.png" /></p>
<blockquote>
<p>Similar to <code>timesince</code> is a <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#timeuntil">timeuntil</a> except that it goes from now to the date in the future.</p>
</blockquote>
<h2 id="random">random</h2>
<p><code>random</code> returns a random item from the given list.</p>
<p>How about we show the user some random saying about money to encourage them to spend money thoughtfully?</p>
<p>Create a list of sayings in the view and pass it to the template:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/views.py</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">filter_expenses_list</span>(<span class="hljs-params">request</span>):</span>
    filter_expenses_list = Expense.objects.order_by(<span class="hljs-string">'-datetime'</span>)

    <span class="hljs-comment"># this is new</span>
    encouragements = [
        <span class="hljs-string">"Opportunity is missed by most people because it is dressed in overalls and looks like work."</span>,
        <span class="hljs-string">"Money is a means to get through this world, but it cannot add a day to our lives."</span>,
        <span class="hljs-string">"It’s good to have money and the things that money can buy, but it’s good too to check up once in a while and make sure that you haven’t lost the things that money can’t buy."</span>,
        <span class="hljs-string">"And when you start putting some rainy-day money aside, you’ll understand that it isn’t “doing nothing.” It’s letting you sleep at night."</span>
    ]

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'tutorial/filtered_expenses.html'</span>, {<span class="hljs-string">'expenses'</span>: filter_expenses_list, <span class="hljs-string">"encouragements"</span>: encouragements}) <span class="hljs-comment"># encouragaments variable is new</span>
</code></pre>
<p>Add this in your html file:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card mb-3"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-header"</span>&gt;</span>Message of encouragement<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-text"</span>&gt;</span>{{ encouragements|random }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>You provided a list of strings and now <code>random</code> each time the page refreshes outputs one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594967416/ukyP-R5Ih.png" alt="random.png" /></p>
<h2 id="unorderedlist">unordered_list</h2>
<p><code>unordere_list</code> creates an html list out of a python list. The list can be nested.</p>
<blockquote>
<p>the list is created without the <code>&lt;ul&gt;</code> tags.</p>
</blockquote>
<p>We've shown a random saying about the money. But what if someone would like to see all of the sayings?
Let's create an html list of all our sayings:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    {{ encouragements|unordered_list }}
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594983023/sJp3SZpWP.png" alt="unordered_list.png" /></p>
<h2 id="add-expense-tags">Add expense tags</h2>
<p>Lets's say you want your users to be able to use tags, so they can group their expenses, etc.</p>
<p>Open <code>models.py</code> and add a tags <code>JSON</code>field:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expense</span>(<span class="hljs-params">models.Model</span>):</span>
    datetime = models.DateTimeField()
    name = models.CharField(max_length=<span class="hljs-number">100</span>)
    amount = models.FloatField()
    tags = models.JSONField()
</code></pre>
<p>Apply the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<p>Go to the <a target="_blank" href="http://127.0.0.1:8000/admin/">admin panel</a> and add few tags in a JSON format.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619594997809/eyk4UlqDq.png" alt="valid_json.png" /></p>
<h2 id="slice">slice</h2>
<p>There is no limit as to how many tags your user enters. But you can't show 25 tags.
You'll use <code>slice</code> to show just the first 2 tags.</p>
<p><code>slice</code> returns a slice of the list, using the same syntax as Python’s list slicing.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row m-4"</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card m-2"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 18rem;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer bg-transparent"</span>&gt;</span>
            {{ expense.tags|slice:":2" }} <span class="hljs-comment">&lt;!-- slice --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595014173/DwAPoM1BH.png" alt="slice.png" /></p>
<p>As you can see, 2 tags are showing at most.</p>
<h2 id="cut">cut</h2>
<p>The Food expense has no tags and it looks super ugly.
You can get rid of the empty list with <code>cut</code>. <code>cut</code> removes all values of the argument from the given string.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row m-4"</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card m-2"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 18rem;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer bg-transparent"</span>&gt;</span>
            {{ expense.tags|slice:":2"|cut:"['']" }} <span class="hljs-comment">&lt;!-- cut added --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now part of the string that exactly matches the argument (<code>['']</code>) will be removed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595027529/1O_UAN1eV.png" alt="cut.png" /></p>
<p>This is not the only thing going on here. As you can see, you left the <code>slice</code> there and added the cut. You can chain filters one after the other.</p>
<h2 id="length">length</h2>
<p>You don't want to show a list of tags on the expense list, you just want to show how many of the tags an expense has.
This can be done with length:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/tutorial/filtered_expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row m-4"</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card m-2"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 18rem;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer bg-transparent"</span>&gt;</span>
            There are {{ expense.tags|length }} tags for this expense. <span class="hljs-comment">&lt;!-- show just the length of the tags list --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595044540/lrOiHbFJC.png" alt="length.png" /></p>
<h2 id="pluralize">pluralize</h2>
<p>The first two that have 2/3 tags look good. But the last one with a single tag still has written "tags" (plural) instead of "tag"(singular).
And you know what? Even that Django has covered - with <code>pluralize</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row m-4"</span>&gt;</span>
    {% for expense in expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card m-2"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 18rem;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer bg-transparent"</span>&gt;</span>
            There are {{ expense.tags|length }} tag{{ expense.tags|pluralize }} for this expense.
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595068376/LklnpVQ9eS.png" alt="pluralize.png" /></p>
<blockquote>
<p>TRICK!</p>
<p>You managed to cover the tag(s) problem, but there is still problem with "are" word ("There ARE 1 tag...").
You can solve that using pluralize:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer bg-transparent"</span>&gt;</span>
  There {{ expense.tags|pluralize:"is,are" }} {{ expense.tags|length }} tag{{ expense.tags|pluralize }} for this expense.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now "is" is used for a singular tag and "are" is used for multiple tags.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595087162/2WknHLS0S.png" alt="pluralize_trick.png" /></p>
</blockquote>
<h2 id="article-model">Article model</h2>
<p>For the next couple of filters, the expenses might not be the best showcase. So let's say you add a blog to lure more clients to use your expense tracker.
Open <code>models.py</code> and add another model, <code>Article</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span>(<span class="hljs-params">models.Model</span>):</span>
    title = models.CharField(max_length=<span class="hljs-number">100</span>)
    content = models.TextField()
</code></pre>
<p>apply the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<p>Add the model to admin:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/admin.py</span>
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Expense, Article

admin.site.register(Expense)
admin.site.register(Article)
</code></pre>
<p>Open the <a target="_blank" href="http://127.0.0.1:8000/admin/">admin panel</a> and add few articles.</p>
<p>If you have them, you need to show them.</p>
<p>Open <code>views.py</code>, retrieve all the articles, and pass them into the template:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> tutorial.models <span class="hljs-keyword">import</span> Expense, Article

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">filter_expenses_list</span>(<span class="hljs-params">request</span>):</span>
    filter_expenses_list = Expense.objects.order_by(<span class="hljs-string">'-datetime'</span>)
    articles = Article.objects.all()

    encouragements = [
        <span class="hljs-string">"..."</span>,
    ]

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'tutorial/filtered_expenses.html'</span>, {<span class="hljs-string">'expenses'</span>: filter_expenses_list, <span class="hljs-string">"encouragements"</span>: encouragements, <span class="hljs-string">"articles"</span>: articles})
</code></pre>
<h2 id="wordcount">wordcount</h2>
<p>We want to list all the articles and show how long each of them is. This can be done with the <code>wordcount</code> filter.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    {% for article in articles %}
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{{ article.title }}: {{ article.content|wordcount }}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595107363/GfltaxlFN.png" alt="wordcount.png" /></p>
<h2 id="truncate">truncate</h2>
<p>On a blog list, you usually show just a part of the text, the whole showing only in detail.
Django has a few built-in possibilities to truncate the text:</p>
<ul>
<li>truncatechars</li>
<li>truncatechars_html</li>
<li>truncatewords</li>
<li>truncatewords_html</li>
</ul>
<p>Since they're so similar, we're going to use 2, but you check the other 2 in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#truncatechars">documentation</a>.</p>
<h3 id="truncatechars">truncatechars</h3>
<p><code>truncatechars</code> truncates a string to the maximum of the specified number of characters. It ends with an ellipsis ("...").</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
    {% for article in articles %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width: 18rem;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ article.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-text"</span>&gt;</span>{{ article.content|truncatechars:150 }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here we're listing the articles in cards. The content of the article is truncated at 150 characters.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595127321/NyQB2K5Pg.png" alt="truncate_chars.png" /></p>
<h3 id="truncatewordshtml">truncatewords_html</h3>
<p><code>truncatewords_html</code> truncates a string after a certain number of words with the respect to html tags. The unclosed html tags are closed immediately after the truncation.
We don't have covered the html characters in the admin (if you want to do that, you can see how it's done in this <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-improving-your-application">post</a>), so we'll have to fake it.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width: 18rem;"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ article.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        {{ "<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'card-text'</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>This text exists to prove<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span> that html tags don't get truncated.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>"|truncatewords_html:10 }} <span class="hljs-comment">&lt;!-- filter added --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here we truncate a string that includes html.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595143674/ZI4Ef1-Wj.png" alt="word_truncate_html.png" /></p>
<p>As you can see, the paragraph tag closes despite the truncation:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619595157213/N6UpbAau8.png" alt="word_truncate_html_inspector.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Many Django filters can be useful for you. If you want to check more than you got to know in this post, you can read about them in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#built-in-filter-reference">documentation</a>.</p>
<p>As for this tutorial, you got to know:</p>
<ul>
<li>different ways to change <strong>cases</strong><ul>
<li><strong>title</strong></li>
<li><strong>capfirst</strong></li>
<li><strong>lower</strong></li>
<li><strong>upper</strong></li>
</ul>
</li>
<li>a way to stile <strong>date</strong></li>
<li>how much time has passed since some date/time with <strong>timesince</strong></li>
<li>how to produce a <strong>random</strong> item from a list</li>
<li>how to create an html <strong>unordered_list</strong> from a Python list</li>
<li>how to get only a part of the list with <strong>slice</strong></li>
<li>how to <strong>cut</strong> something out of a string</li>
<li>how to find out the <strong>length</strong> of the value</li>
<li>how to cover case, where there can be one or multiple things with <strong>pluralize</strong></li>
<li>how to do a <strong>wordcount</strong></li>
<li>multiple possibilities for <strong>truncating</strong> text:<ul>
<li><strong>truncatechars</strong></li>
<li><strong>truncatewords_html</strong></li>
</ul>
</li>
</ul>
<p><sub>Cover image by Daniel Mena from Pixabay</sub></p>
]]></content:encoded></item><item><title><![CDATA[Fluent in Django: 8 Django template tags you should know]]></title><description><![CDATA[Intro
Django templating language (Django's default out-of-the-box templating language) comes with dozens of tags that make your template powerful and allows you to do many many things.
Tags provide arbitrary logic in the rendering process and they ar...]]></description><link>https://girlthatlovestocode.com/django-template-tags</link><guid isPermaLink="true">https://girlthatlovestocode.com/django-template-tags</guid><category><![CDATA[Django]]></category><category><![CDATA[Python]]></category><category><![CDATA[template]]></category><category><![CDATA[templates]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Mon, 19 Apr 2021 12:53:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836699006/C9VhSgiUH.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="intro">Intro</h2>
<p>Django templating language (Django's default out-of-the-box templating language) comes with dozens of tags that make your template powerful and allows you to do many many things.
Tags provide arbitrary logic in the rendering process and they are located inside <code>{% %}</code> (unlike variables that are in the double curly braces - <code>{{ }}</code>).</p>
<p>Some of the tags you probably know are:</p>
<ul>
<li>for loop (<code>{% for i in numbers %}</code>)</li>
<li>if (<code>{% if i &gt; 10 %}</code>)</li>
<li>extends (<code>{% extends "base.html" %}</code>)</li>
<li>block (<code>{% block title %}</code>)</li>
</ul>
<p>But there are less known tags that can make your life easier. To get to know some of them, we'll work on the expense tracker.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>You will need the basic knowledge of Django. If you don't feel comfortable with Django yet, try <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">this beginner-friendly tutorial</a>.</p>
<h2 id="initial-setup">Initial setup</h2>
<p>Start with setting up a new Django project:</p>
<pre><code class="lang-sh">$ mkdir django_template_tutorial
$ <span class="hljs-built_in">cd</span> django_template_tutorial
$ python3.9 -m venv venv
$ <span class="hljs-built_in">source</span> venv/bin/activate
(venv)$ pip install Django
(venv)$ django-admin startproject django_templates .
</code></pre>
<p>Create a new app:</p>
<pre><code class="lang-sh">(venv)$ django-admin startapp tutorial
</code></pre>
<p>and register it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># django_templates/settings.py</span>

INSTALLED_APPS = [
    <span class="hljs-string">'django.contrib.admin'</span>,
    <span class="hljs-string">'django.contrib.auth'</span>,
    <span class="hljs-string">'django.contrib.contenttypes'</span>,
    <span class="hljs-string">'django.contrib.sessions'</span>,
    <span class="hljs-string">'django.contrib.messages'</span>,
    <span class="hljs-string">'django.contrib.staticfiles'</span>,
    <span class="hljs-string">'tutorial'</span>,
]
</code></pre>
<p>Create a model called <code>Expense</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expense</span>(<span class="hljs-params">models.Model</span>):</span>
    datetime = models.DateTimeField()
    name = models.CharField(max_length=<span class="hljs-number">100</span>)
    amount = models.FloatField()
</code></pre>
<p>Create and run the migrations:</p>
<pre><code class="lang-sh">(venv)$ python manage.py makemigrations
(venv)$ python manage.py migrate
</code></pre>
<blockquote>
<p>If you got lost during the initial setup, I encourage you to go <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">back to basics</a>.</p>
</blockquote>
<p>Create a folder called <code>templates</code> inside the <code>tutorial</code> folder and inside it, another folder, again called <code>tutorial</code>.
Inside this structure, create a template called <code>expenses.html</code>:</p>
<pre><code><span class="hljs-selector-tag">django_templates</span>
    └── <span class="hljs-selector-tag">tutorial</span>
        └── <span class="hljs-selector-tag">templates</span>
            └── <span class="hljs-selector-tag">tutorial</span>
                └── <span class="hljs-selector-tag">expenses</span><span class="hljs-selector-class">.html</span>
</code></pre><blockquote>
<p>Confused about the directory structure? Read about Django template resolving in <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">first part</a> (<strong>Template</strong> chapter).</p>
</blockquote>
<p>Now we need to create an url where our template will be shown.</p>
<p>Open <code>django_templates/urls.py</code> and include tutorial's urls in it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># django_templates/urls.py</span>

<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include  <span class="hljs-comment"># this is new</span>


urlpatterns = [
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
    path(<span class="hljs-string">''</span>, include(<span class="hljs-string">'tutorial.urls'</span>)), <span class="hljs-comment"># this is new</span>
]
</code></pre>
<p>We haven't created <code>tutorial/urls.py</code> yet. Create the file and define just the root url:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/urls.py</span>

<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> tutorial <span class="hljs-keyword">import</span> views

urlpatterns = [
    path(<span class="hljs-string">''</span>, views.expenses_list),
]
</code></pre>
<p>And the last thing is to create a view called <code>expenses_list</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/views.py</span>

<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> tutorial.models <span class="hljs-keyword">import</span> Expense


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">expenses_list</span>(<span class="hljs-params">request</span>):</span>
    expenses = Expense.objects.all()

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'tutorial/expenses.html'</span>, {<span class="hljs-string">'expenses'</span>: expenses})
</code></pre>
<p>Run the server:</p>
<pre><code class="lang-sh">(venv)$ python manage.py runserver
</code></pre>
<p>If you navigate to http://127.0.0.1:8000, you'll see an empty page.
Now we can finally get to our template.</p>
<h2 id="starting-with-the-template">Starting with the template</h2>
<p>In the real-world application, you'd make a base template and extended it with <code>{% extends %}</code> tag, but we'll have only one template, so add the following:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/expenses.html--&gt;</span>

<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Expenses<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mt-5"</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="lorem">lorem</h3>
<p>You could just start with listing the expenses, but that wouldn't look very nice, right?
You should write some intro in the beginning, but what?</p>
<p>You'll get to that later, for now, just use the built-in lorem-ipsum generator:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"jumbotron"</span>&gt;</span>
        {% lorem 2 p random %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>If you refresh the page, there will be 2 paragraphs from Lorem ipsum (that don't start with those words)!</p>
<p><code>lorem</code> has 3 parameters and all three are optional:</p>
<pre><code class="lang-html">{% lorem [count] [method] [random] %}
</code></pre>
<ul>
<li><strong>number</strong> of the words/paragraphs that will be generated. It can be a number or a variable. The default value is 1.</li>
<li><strong>method</strong> will generate either:<ul>
<li>words (<code>w</code>)</li>
<li>HTML paragraphs (<code>p</code>)</li>
<li>plain text paragraphs (<code>b</code> - this is the default value)</li>
</ul>
</li>
<li><strong>random</strong>  - the generated text won't start with 'Lorem ipsum'. The default is False. I think this is useful only if 'Lorem ipsum is bugging you (it does bug me and I usually add the random parameter).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836442888/5TBZmERc1.png" alt="lipsum.png" /></p>
<blockquote>
<p>You can read more on <code>lorem</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#lorem">documentation</a>.</p>
</blockquote>
<h2 id="empty">empty</h2>
<p>Now let's list all the expenses we have. We don't have any expenses yet, but Django can handle that.
We just need to add an <code>{% empty %}</code> tag inside the for loop to cover that.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

{% for expense in expenses %}
    {{ expense }}
{% empty %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span>&gt;</span>
        There are no expenses yet.
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endfor %}
</code></pre>
<p>If you refresh the page, you'll see that there's an alert saying there are no expenses yet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836460801/5AFCIQug8.png" alt="empty.png" /></p>
<p>The empty tag replaces the need for an if tag checking if the array is not empty.
If the array is empty, the part between the <code>{% empty %}</code> and <code>{% endfor %}</code> is shown.
If the array is not empty, that part will simply get skipped.</p>
<p>Let's check that.</p>
<blockquote>
<p>You can read more on <code>empty</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#for-empty">documentation</a>.</p>
</blockquote>
<h2 id="adding-the-expenses">Adding the expenses</h2>
<p>Stop the server with <code>CtrlC</code>, create the superuser and start the server again:</p>
<pre><code class="lang-sh">(venv)$ python manage.py createsuperuser
(venv)$ python manage.py runserver
</code></pre>
<p>Register the <code>Expense</code> model on the admin site in the <code>admin.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/admin.py</span>

<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Expense

admin.site.register(Expense)
</code></pre>
<p>Open http://127.0.0.1:8000/admin/, log in with the superuser you created, and add 5 expenses. 
Make 3 of those on the same date.</p>
<p>Change the expense display in <code>expenses.html</code> so it will show the details of each expense in a table:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mt-5"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"jumbotron"</span>&gt;</span>
        {% lorem 2 p random %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
        {% for expense in expenses %}
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% empty %}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span>&gt;</span>
                There are no expenses yet.
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836476649/HgTnq4WBT.png" alt="starting.png" /></p>
<h2 id="cycle">cycle</h2>
<p>Let's say we want to add a little color to the expense table. We will alternate blue and gray with the white color.
We can create rows of that color with <a target="_blank" href="https://getbootstrap.com/docs/4.0/content/tables/#contextual-classes">Bootstrap classes</a> - 
<code>table-info</code>, <code>table-light</code> and <code>table-active'</code> classes.
But we need a way to alternate those classes.</p>
<p>This is what <code>cycle</code> is for.</p>
<p><code>cycle</code> outputs one of the arguments each time the tag is encountered (usually in the for-loop, but not necessarily).
When all arguments are exhausted, the cycle returns to the first argument.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--expenses.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    {% for expense in grouped_expenses %}
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"{% cycle 'table-info' 'table-light' 'table-active' 'table-light' %}"</span>&gt;</span> <span class="hljs-comment">&lt;!-- cycle added --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{  expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>{{  expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {% empty %}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span>&gt;</span>
            There are no expenses yet.
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p><code>cycle</code> in our case produces the Bootstrap class on each iteration. The first time will be <code>table-info</code>, the second time <code>table-light</code>, the third time <code>table-active</code> and so on and on, for every row in the table.</p>
<p>Check it out in the browser:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836494271/GRCgDrQRF.png" alt="cycle.png" /></p>
<blockquote>
<p>You can read more on <code>cycle</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#cycle">documentation</a>.</p>
</blockquote>
<h2 id="regroup">regroup</h2>
<p><code>{% regroup %}</code> groups a list of similar objects in groups based on a common attribute.
We'll use the <code>regroup</code> to group our expenses based on the expense tag. </p>
<p>Open <code>models.py</code> and add a tag to your <code>Expense</code> model. </p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/models.py</span>

<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expense</span>(<span class="hljs-params">models.Model</span>):</span>
  <span class="hljs-comment"># this is new:</span>
    MISCELLANEOUS = <span class="hljs-string">"misc"</span>
    GROCERIES = <span class="hljs-string">"groc"</span>
    HEALTH = <span class="hljs-string">"hlth"</span>
    BILLS = <span class="hljs-string">"bill"</span>
    EXPENSE_TAGS = [
        (MISCELLANEOUS, <span class="hljs-string">'miscellaneous'</span>),
        (GROCERIES, <span class="hljs-string">'groceries'</span>),
        (HEALTH, <span class="hljs-string">'health'</span>),
        (BILLS, <span class="hljs-string">'bills'</span>),
    ]

    datetime = models.DateTimeField()
    name = models.CharField(max_length=<span class="hljs-number">100</span>)
    amount = models.FloatField()
    tag = models.CharField(max_length=<span class="hljs-number">20</span>, choices=EXPENSE_TAGS, default=MISCELLANEOUS) <span class="hljs-comment"># this is new</span>
</code></pre>
<blockquote>
<p>Check how <a target="_blank" href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#choices">the choices field</a> is created.</p>
</blockquote>
<p>You added a <code>tag</code> <code>CharField</code> with predefined choices that are listed in <code>EXPENSE_TAGS</code>. 
We set the default value, so every expense, including the already created ones, has a tag.
Navigate to http://127.0.0.1:8000/admin/tutorial/expense/ and change tags for a few of the expenses (make sure at least three have the same tag).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836506971/KEN6rQZnE.png" alt="admin_tag.png" /></p>
<p>You might imagine that <code>regroup</code> orders the input. <strong>It doesn't</strong>
The input has to be ordered from the start. It just checks when the selected attribute changes.
So if the input isn't organized, you will have more groups with the same attribute.</p>
<p>That's why we need to organize our expenses by tag for this part.
Open <code>views.py</code> and create another object to pass to the template:</p>
<pre><code class="lang-python"><span class="hljs-comment"># blog/views.py</span>

<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> tutorial.models <span class="hljs-keyword">import</span> Expense


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">expenses_list</span>(<span class="hljs-params">request</span>):</span>
    expenses = Expense.objects.all()
    tag_expenses = Expense.objects.order_by(<span class="hljs-string">'tag'</span>)

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'tutorial/expenses.html'</span>, {<span class="hljs-string">'expenses'</span>: expenses, <span class="hljs-string">'tag_expenses'</span>: tag_expenses })
</code></pre>
<p>You made the same query as for the expenses, but you ordered it by the <code>tag</code> attribute.</p>
<blockquote>
<p>We're passing the same list of objects to the same template because this is the simplest way for a tutorial. 
In reality, you'd probably want to have a different page and you wouldn't query the DB twice.</p>
</blockquote>
<p>Open <code>expenses.html</code> and add this code at the bottom of the <code>container div</code>:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-5"</span>&gt;</span>Expenses by tag<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

{% regroup tag_expenses by tag as grouped_expenses %}
    {% for tag in grouped_expenses %}
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table mb-5"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">colspan</span>=<span class="hljs-string">"4"</span>&gt;</span>{{ tag.grouper }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
            {% for expense in tag.list %}
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"{% cycle 'table-info' 'table-light' 'table-active' 'table-light' %}"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.tag }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            {% endfor %}
            <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
    {% endfor %}
</code></pre>
<p>In this code, there are 3 important parts:</p>
<ul>
<li><code>{% regroup tag_expenses by tag as grouped_expenses %}</code></li>
<li><code>{{ tag.grouper }}</code></li>
<li><code>{% for expense in tag.list %}</code></li>
</ul>
<p><code>{% regroup %}</code> creates a list of group objects. A group object is a tuple-like object with two items.</p>
<p>The first one is a <code>grouper</code>.
This is the item the group was grouped by (in our case, each of the tags used).</p>
<p>The second one is a list of all the items in this group (in our case, all the expenses with a certain tag).
So now you don't access expense directly as you did in the first case, but with <code>tag.list</code>.</p>
<pre><code class="lang-html">{% for expense in expenses %}

<span class="hljs-comment">&lt;!-- versus --&gt;</span>

{% for expense in tag.list %}
</code></pre>
<p>Everything else is either Bootstrap or something you already saw.
Refresh the page. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836527229/Ioa_4oaYz.png" alt="expenses_by_tag.png" /></p>
<blockquote>
<p>You can read more on <code>regroup</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#regroup">documentation</a>.</p>
</blockquote>
<h2 id="resetcycle">resetcycle</h2>
<p>As you can see in the picture above, <code>cycle</code> doesn't start its cycle again with the new table, but continues it.
So the first table starts with blue, but the next one starts with white.
If you want the tables to look consistent, you need to reset the cycle each time the new table starts with <code>{% resetcycle %}</code>.</p>
<p>Add it between the ends of the outer and inner for loop:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/expenses.html--&gt;</span>

 {% for tag in grouped_expenses %}
    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table mb-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">colspan</span>=<span class="hljs-string">"4"</span>&gt;</span>{{ tag.grouper }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
        {% for expense in tag.list %}
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"{% cycle 'table-info' 'table-light' 'table-active' 'table-light' %}"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.tag }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
    {% resetcycle %} <span class="hljs-comment">&lt;!-- if you want each new table to start with blue row, you have to reset the cycle --&gt;</span>
{% endfor %}
</code></pre>
<blockquote>
<p>You can read more on <code>resetcycle</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#resetcycle">documentation</a>.</p>
</blockquote>
<h2 id="comment">comment</h2>
<p>Maybe you're not sure what the <code>resetcycle</code> does? When that happens, it's usually a good idea to comment that part out and see what happens?</p>
<p>But if you try to comment it out with html comment, like this:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- {% resetcycle %} --&gt;</span>
</code></pre>
<p>you'll see that this doesn't work.</p>
<p>You can comment it with the <code>{% comment %}</code> and you can even add a note.</p>
<pre><code class="lang-html">{% comment "Uncomment if you want the table color cycle to reset" %}
{% resetcycle %}
{% endcomment %}
</code></pre>
<blockquote>
<p>Alternatively, you can do it like this:</p>
<pre><code class="lang-html">{# {% resetcycle %} #}
</code></pre>
<p>You can read more on <code>comment</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#comment">documentation</a>.</p>
</blockquote>
<h2 id="firstof">firstof</h2>
<p><code>firstof</code> finds the first "truthy" value and outputs it.</p>
<blockquote>
<p>Python treats many values as "truthy" ones. These are non-empty strings, non-empty lists, non-empty sets, non-empty dictionaries, instances of your classes, True, integers/floats different than 0. As "falsy" it treats False, 0, None, empty lists, empty sets, empty dictionaries, empty strings, etc. </p>
</blockquote>
<p>Let's say you have a dictionary of repetitive monthly expenses. 
If the expense has been entered (paid), the value is set either to <code>None</code> or <code>0</code>. If not, the value is some string about the expense.
You want to show the notice, alerting the user of the first expense that hasn't been entered yet (meaning it hasn't been paid yet).</p>
<p>Let's first create the dictionary.</p>
<p>Open <code>views.py</code> and add the dictionary:</p>
<pre><code class="lang-python">
<span class="hljs-comment"># tutorial/views.py</span>

<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> tutorial.models <span class="hljs-keyword">import</span> Expense


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">expenses_list</span>(<span class="hljs-params">request</span>):</span>
    expenses = Expense.objects.all()
    tag_expenses = Expense.objects.order_by(<span class="hljs-string">'tag'</span>)

    <span class="hljs-comment"># dictionary with data</span>
    monthly_expenses = {
        <span class="hljs-string">"rent"</span>: <span class="hljs-number">0</span>,
        <span class="hljs-string">"insurance"</span>: <span class="hljs-literal">None</span>,
        <span class="hljs-string">"internet"</span>: <span class="hljs-string">"You haven't payed your internet bill (25.00€) yet."</span>,
        <span class="hljs-string">"mobile_phone"</span>: <span class="hljs-string">"You haven't payed your mobile phone bill (32.50€) yet."</span>
    }

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'tutorial/expenses.html'</span>, {<span class="hljs-string">'expenses'</span>: expenses, <span class="hljs-string">'tag_expenses'</span>: tag_expenses, <span class="hljs-string">'monthly_expenses'</span>: monthly_expenses}) <span class="hljs-comment"># dictionary passed to the template</span>
</code></pre>
<p>Now you can use the <code>firstof</code> to show the first unpaid expense somewhere at the top of the template:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--expenses.html--&gt;</span>

    {% firstof monthly_expenses.rent monthly_expenses.insurance monthly_expenses.internet monthly_expenses.mobile_phone as first_unpaid %}
    {% if first_unpaid %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-warning"</span>&gt;</span>
        You haven't paid your {{ first_unpaid }} yet.
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endif %}
</code></pre>
<p>You've listed all the variables you want <code>firstof</code> to check and Django went like this (read in Django voice):</p>
<ul>
<li><code>monthly_expenses.rent</code> -&gt; rent is Falsy(<code>0</code>), I don't care about this</li>
<li><code>monthly_expenses.insurance</code> -&gt; insurance is Falsy(<code>None</code>), I don't care about this</li>
<li><code>monthly_expenses.internet</code> -&gt; this is a Truthy value, I'm outputting this</li>
<li><code>monthly_expenses.mobile_phone</code> -&gt; although this is a Truthy value, I don't care about this, I already found my value</li>
<li>You could provide an additional default value that would be assigned if nothing else would</li>
</ul>
<p>Then you assigned the first truthy value to a variable named <code>first_unpaid</code> and you can now use it in your code.
You checked if it exists and if it does, you displayed a notification about the first unpaid bill.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836542929/cara-gotn.png" alt="firstof.png" /></p>
<blockquote>
<p>You can read more on <code>firstof</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#firstof">documentation</a>.</p>
</blockquote>
<h2 id="ifchanged">ifchanged</h2>
<p><code>{% ifchanged %}</code> can only be used in a loop. It can either check if the content in the block changed and if it did, it displays it, or
checks if one or more of the given variables changed and displays whatever is between the tags.
You can also use an <code>else</code> clause within (the same way you would use else in a simple if).</p>
<p>For now we displayed unordered expenses under <code>All expenses</code> title.
Open <code>views.py</code> and change <code>expenses = Expense.objects.all()</code> to this:</p>
<pre><code class="lang-python"><span class="hljs-comment"># views.py</span>

expenses = Expense.objects.order_by(<span class="hljs-string">'-datetime'</span>)
</code></pre>
<p>Everything else in <code>views.py</code> remains unchanged.</p>
<p>Now edit the table under <code>All expenses</code> table to include an <code>{% ifchanged %}</code>tags:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--tutorial/templates/tutorial/expenses.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
        {% for expense in expenses %}
            {% ifchanged %}<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">colspan</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table-dark"</span>&gt;</span>{{ expense.datetime|date:"F" }}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>{% endifchanged %} <span class="hljs-comment">&lt;!-- this is new --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"{% cycle 'table-info' 'table-light' 'table-active' 'table-light' %}"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ expense.datetime }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{  expense.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{  expense.amount }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% empty %}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span>&gt;</span>
                There are no expenses yet.
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p>If the month changes, the code inside the <code>{% ifchanged %}</code> tags is displayed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618836558021/kWRPBtJQJ.png" alt="ifchanged.png" /></p>
<blockquote>
<p>For this to work properly, you have to have expenses from at least two different months.</p>
<p>You can read more on <code>ifchanged</code> in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#ifchanged">documentation</a>.</p>
</blockquote>
<h2 id="conclusion">Conclusion</h2>
<p>In this post you learned about 8 tags:</p>
<ul>
<li>lorem</li>
<li>empty</li>
<li>cycle</li>
<li>regroup</li>
<li>resetcycle</li>
<li>comment</li>
<li>firstof</li>
<li>ifchanged</li>
</ul>
<p>You might use them often (I use <code>{% empty %}</code> regularly) or you might never use a tag. Don't force them, use them cautiously.
However, it's good to know they're there and it's fun to feel like a magician when you produce something with just one line of code.</p>
<p>Those are not all the tags, you can see all of them in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/templates/builtins/">documentation</a>.
Here I also presented one way of using it, there can be more than one way or they have additional parameters that we didn't explore.
When your building your next Django project and trying to do something in the template, remember there might be a tag for this.</p>
]]></content:encoded></item><item><title><![CDATA[8 explained examples of list comprehension in Python]]></title><description><![CDATA[What is list comprehension
List comprehension is a concise way used instead of for-loop when you want to create a new list based on another iterable (list, tuple, dictionary, set, string, generator, ...).
You get to do this:
[do_this(element) for ele...]]></description><link>https://girlthatlovestocode.com/8-explained-examples-of-list-comprehension-in-python</link><guid isPermaLink="true">https://girlthatlovestocode.com/8-explained-examples-of-list-comprehension-in-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Tue, 13 Apr 2021 07:08:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618297690288/It0RVAiCH.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="what-is-list-comprehension">What is list comprehension</h2>
<p>List comprehension is a concise way used instead of for-loop when you want to create a new list based on another iterable (list, tuple, dictionary, set, string, generator, ...).</p>
<p>You get to do this:</p>
<pre><code class="lang-python">[do_this(element) <span class="hljs-keyword">for</span> element <span class="hljs-keyword">in</span> thislist <span class="hljs-keyword">if</span> thisistrue]
</code></pre>
<p>instead of this:</p>
<pre><code class="lang-python">my_list = []
<span class="hljs-keyword">for</span> element <span class="hljs-keyword">in</span> thislist:
    <span class="hljs-keyword">if</span> thisistrue:
        my_list.append(do_this(element))
</code></pre>
<p>It's easily recognizable and more readable than (at least) 3-lines long for-loop.
It's <a target="_blank" href="https://www.linkedin.com/pulse/list-comprehension-python-always-faster-than-alex-falkovskiy">usually faster</a> and helps you maintain your code clean and simple.
It's especially neater when you want to find the common elements from two lists. You'd need two for loops for that and still only one "not-that-complicated" line for list comprehension.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618297019860/dUFycre5O.png" alt="list_comprehension_explained.png" /></p>
<p>The result of a list comprehension is always a new list, that's why the expression is in square brackets (there is also a dictionary comprehension, where the result is a dictionary and set comprehension where the result is a dictionary/set accordingly).</p>
<p>There are three parts of the comprehension inside the brackets:</p>
<ul>
<li>what to do (e.g. add 2 to each element)</li>
<li>for what in which list (e.g. for element in the list of numbers)</li>
<li>when (e.g. when the element is dividable by two)</li>
</ul>
<blockquote>
<p>The third part, <code>if</code>, can be omitted. In that case, the expression will be performed on each element of the old list and the length of the new and old list will be the same.</p>
</blockquote>
<p>A very simple showcase of a list comprehension would be this:</p>
<pre><code class="lang-python">[x+<span class="hljs-number">2</span> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>]]

<span class="hljs-comment"># result: [4, 5, 6]</span>
</code></pre>
<p>You add 2 to <strong>each item</strong> in the list (<code>[2+2, 3+2, 4+2]</code>) because there is no condition.</p>
<p>But let's say we want the addition to be performed only on even numbers:</p>
<pre><code class="lang-python">[x+<span class="hljs-number">2</span> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>] <span class="hljs-keyword">if</span> x % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>]

<span class="hljs-comment"># result: [4, 6]</span>
</code></pre>
<p>Now the addition is performed only on 2 and 4 (<code>[2+2, 4+2]</code>). 3 is not an even number, so it is omitted from the creation of a new list.</p>
<p>Those are two very simple cases, just enough for you to get an idea.
In the real world, you probably won't need to add a number to a list of numbers.
List comprehension in the real world is often used to perform some kind of filtering.</p>
<h2 id="filtering">Filtering</h2>
<p>When you want to create a new list with just some of the elements from the old list, you set a condition with <code>if</code> that will let only some of the elements pass.
You can either do something with the elements that match the condition (<code>new_x = x+2</code>) or not (<code>new_x = x</code>).</p>
<h3 id="simple-filtering">Simple filtering</h3>
<p>You know those "The hottest day this summer" news titles?
Let's say you have the list of the daily temperatures from the summer and you want to get only the temperature higher than 30°C.
This is how you do it:</p>
<pre><code class="lang-python">all_temperatures = [<span class="hljs-number">28</span>, <span class="hljs-number">23</span>, <span class="hljs-number">38</span>, <span class="hljs-number">32</span>, <span class="hljs-number">28</span>, <span class="hljs-number">31</span>, <span class="hljs-number">29</span>, <span class="hljs-number">33</span>]

highest_temperatures = [temperature <span class="hljs-keyword">for</span> temperature <span class="hljs-keyword">in</span> all_temperatures <span class="hljs-keyword">if</span> temperature &gt; <span class="hljs-number">30</span>]

<span class="hljs-comment"># result: [38, 32, 31, 33]</span>
</code></pre>
<p>In this case, you didn't change the elements. You just took the numbers higher than 30 from the <code>all_temperatures</code> list and put them into the <code>highest_temperatures</code> list.
The <code>all_temperatures</code> list is unchanged.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618297037140/QTSPMtLZI.png" alt="simple_filter.png" /></p>
<h3 id="filtering-based-on-the-length-of-the-element">Filtering based on the length of the element</h3>
<p>You got a list of messages from your users. The field was required, so some of them just wrote few random letters to skip it.
You want to filter out the ones with some values - the string has to be at least 10 characters long:</p>
<pre><code class="lang-python">messages = [<span class="hljs-string">'Praesent orci nulla, pellentesque a consectetur id.'</span>, <span class="hljs-string">'/'</span>, <span class="hljs-string">'zblj'</span>, <span class="hljs-string">'Aliquam pellentesque diam et nibh hendrerit semper. '</span>, <span class="hljs-string">'test'</span>]
valuable_messages = [message <span class="hljs-keyword">for</span> message <span class="hljs-keyword">in</span> messages <span class="hljs-keyword">if</span> len(message) &gt; <span class="hljs-number">10</span>]

<span class="hljs-comment"># result: ['Praesent orci nulla, pellentesque a consectetur id.', 'Aliquam pellentesque diam et nibh hendrerit semper. ']</span>
</code></pre>
<p>As in the previous case, you didn't do anything with the element on the list. You just checked if it's long enough and if it is, you added it to the new list.</p>
<h3 id="filtering-based-on-part-of-the-tuple">Filtering based on part of the tuple</h3>
<p>Let's say you have a tuple of tuples with a name and a grade a student got for the test. Some of the students were sick, so they weren't graded and now you want to know which of the students you need to prepare another test.</p>
<pre><code class="lang-python">grades = ((<span class="hljs-string">'Anna'</span>, <span class="hljs-string">'B'</span>), (<span class="hljs-string">'May'</span>, <span class="hljs-string">'A'</span>), (<span class="hljs-string">'Tina'</span>, <span class="hljs-string">''</span>), (<span class="hljs-string">'Claire'</span>, <span class="hljs-string">''</span>), (<span class="hljs-string">'Beth'</span>, <span class="hljs-string">'A'</span>))

ungraded = [name <span class="hljs-keyword">for</span> name, grade <span class="hljs-keyword">in</span> grades <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> grade]

<span class="hljs-comment"># result: ['Tina', 'Claire']</span>
</code></pre>
<p>As you can see, this is not a list, but a tuple of tuples. In the list comprehension, you declared that the first part of the inside tuple is called <code>name</code> and the second one is called <code>grade</code> (this is called tuple unpacking).
Those names are of your choosing and matter only for readability purposes. For Python's sake, they could be called <code>zblj</code> and <code>gn</code>.
You take the name from each tuple in the outer tuple and put it in the new list (there won't be grades listed in the new list, just names). But the element (name) goes to the new list only if the second part of the tuple (grade) is an empty string. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618297053688/DvhZ8KgXh.png" alt="list_tuple.png" /></p>
<p>This is the only case we didn't create a list out of the list but out of a tuple. It doesn't matter what the source object is, only that is iterable. The outcome, however, is always a list.</p>
<h3 id="filtering-and-changing-the-element">Filtering and changing the element</h3>
<p>If you need to extract numbers from the list of strings, you can check if the string contains only digits and if it does, you can convert it to an integer.</p>
<pre><code class="lang-python">alphanumeric = [<span class="hljs-string">"47"</span>, <span class="hljs-string">"abcd"</span>, <span class="hljs-string">"21st"</span>, <span class="hljs-string">"n0w4y"</span>, <span class="hljs-string">"test"</span>, <span class="hljs-string">"55123"</span>]
numbers = [int(string) <span class="hljs-keyword">for</span> string <span class="hljs-keyword">in</span> alphanumeric <span class="hljs-keyword">if</span> string.isdigit()]

<span class="hljs-comment"># result: [47, 55123]</span>
</code></pre>
<p>On the new list are the elements from the old list that contained only digits and were transformed to integers.</p>
<h2 id="working-with-more-than-one-list">Working with more than one list</h2>
<p>Another possibility where list comprehension can be useful is when you need to somehow combine two or more lists.</p>
<h3 id="combining-all-the-elements">Combining all the elements</h3>
<p>You want to order mobile phones for your store. Your boss told you which color and which models to order.
To make it easy for yourself, you can combine all the selected colors with all the selected models:</p>
<pre><code class="lang-python">colors = [<span class="hljs-string">"red"</span>, <span class="hljs-string">"blue"</span>, <span class="hljs-string">"black"</span>]
models = [<span class="hljs-string">"12"</span>, <span class="hljs-string">"12 mini"</span>, <span class="hljs-string">"12 Pro"</span>]

order = [(model, color) <span class="hljs-keyword">for</span> model <span class="hljs-keyword">in</span> models <span class="hljs-keyword">for</span> color <span class="hljs-keyword">in</span> colors]

<span class="hljs-comment"># result: [('12', 'red'), ('12', 'blue'), ('12', 'black'), ('12 mini', 'red'), ('12 mini', 'blue'), ('12 mini', 'black'), ('12 Pro', 'red'), ('12 Pro', 'blue'), ('12 Pro', 'black')]</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618297067995/I9jonynUX.png" alt="tuple_from_two_lists.png" /></p>
<p>Here you combined <strong>every</strong> item from the first list with <strong>every</strong> item on the second list. The length of the new list will be the product of both lengths (<code>len(list_1) * len(list_2)</code>)</p>
<h3 id="common-elements">Common elements</h3>
<p>Here's one for the Disney fans. You have a list of all the characters from Frozen. And you have a list of all the Disney princesses.
Now you would like to know which Disney princesses are in the Frozen movie.</p>
<pre><code class="lang-python">frozen = [<span class="hljs-string">"Anna"</span>, <span class="hljs-string">"Elsa"</span>, <span class="hljs-string">"Sven"</span>, <span class="hljs-string">"Olaf"</span>]
princesses = [<span class="hljs-string">"Rapunzel"</span>, <span class="hljs-string">"Elsa"</span>, <span class="hljs-string">"Anna"</span>, <span class="hljs-string">"Ariel"</span>]

princesses_from_frozen = [frozen_char <span class="hljs-keyword">for</span> frozen_char <span class="hljs-keyword">in</span> frozen <span class="hljs-keyword">for</span> princess <span class="hljs-keyword">in</span> princesses <span class="hljs-keyword">if</span> frozen_char == princess]
</code></pre>
<p>In this case, you go through all the elements in the first list and you compare every single element with all the elements from the second list.
The new list contains only the elements that appeared on both lists.</p>
<p>This might be the easiest to explain if you see how this would look with a for-loop:</p>
<pre><code class="lang-python">princesses_from_frozen = []
<span class="hljs-keyword">for</span> frozen_char <span class="hljs-keyword">in</span> frozen: <span class="hljs-comment"># loop through the first list</span>
    <span class="hljs-keyword">for</span> princess <span class="hljs-keyword">in</span> princesses: <span class="hljs-comment"># loop through the second list</span>
        <span class="hljs-keyword">if</span> frozen_char == princess: <span class="hljs-comment"># compare the element from the first loop with the element from the second one</span>
            princesses_from_frozen.append(frozen_char)
</code></pre>
<p>If you didn't previously, now you probably get the beauty of list comprehension?</p>
<h3 id="combining-elements-with-the-same-position">Combining elements with the same position</h3>
<pre><code class="lang-python">names = [<span class="hljs-string">"John"</span>, <span class="hljs-string">"Mary"</span>, <span class="hljs-string">"Lea"</span>]
surnames = [<span class="hljs-string">"Smith"</span>, <span class="hljs-string">"Wonder"</span>, <span class="hljs-string">"Singer"</span>]
ages = [<span class="hljs-string">"22"</span>, <span class="hljs-string">"19"</span>, <span class="hljs-string">"25"</span>]

combined = [F<span class="hljs-string">"{name} {surname} - {age}"</span> <span class="hljs-keyword">for</span> name, surname, age <span class="hljs-keyword">in</span> zip(names, surnames, ages)]

<span class="hljs-comment"># result: ['John Smith - 22', 'Mary Wonder - 19', 'Lea Singer - 25']</span>
</code></pre>
<p>Here we need to use the Python <code>zip</code> function. </p>
<blockquote>
<p><code>zip</code> function returns a zip object, which is an iterator of tuples where the elements on the same position from different lists are paired together.</p>
<p>So, <code>zip(names, surnames)</code> would need to be turned to something readable with 
<code>tuple()</code>:</p>
<p><code>print(tuple(zip(names, surnames)))</code></p>
<p>and would return: </p>
<p><code>(('John', 'Smith'), ('Mary', 'Wonder'), ('Lea', 'Singer'))</code>.</p>
</blockquote>
<p>After we created a zip object, we assigned names for each element in the tuple - <code>name, surname, age</code> and combined all three in a string for each tuple (<code>F"{name} {surname} - {age}"</code>). 
If the lists are of different lengths, the zip will work with the shortest list. So the length of the new list will be the same as the length of the shortest list.</p>
<h2 id="using-it-with-function">Using it with function</h2>
<p>If you need to do quite a lot with the elements, you can use a function in the expression and do the logic in the function. That way, your list comprehension stays short and readable.</p>
<h3 id="convert-euros-to-dollars">Convert euros to dollars</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">convert_to_dol</span>(<span class="hljs-params">eur</span>):</span>
    <span class="hljs-keyword">return</span> round(eur * <span class="hljs-number">1.19</span>, <span class="hljs-number">2</span>)


prices = [<span class="hljs-number">22.30</span>, <span class="hljs-number">12.00</span>, <span class="hljs-number">0.99</span>, <span class="hljs-number">1.10</span>]
dollar_prices = [convert_to_dol(price) <span class="hljs-keyword">for</span> price <span class="hljs-keyword">in</span> prices]

<span class="hljs-comment">#result: [26.54, 14.28, 1.18, 1.31]</span>
</code></pre>
<p>The above example would also work written like this:</p>
<pre><code class="lang-python">dollar_prices = [round(price * <span class="hljs-number">1.19</span>, <span class="hljs-number">2</span>) <span class="hljs-keyword">for</span> price <span class="hljs-keyword">in</span> prices]
</code></pre>
<p>but it's not as readable, right?</p>
<h2 id="conclusion">Conclusion</h2>
<p>List comprehension can be confusing at first, but it's really worth learning. 
You might have to do few more cases, but after a while, it will be easier to make sense of a list comprehension than of a for loop, I promise.
However, don't go switching all of your for-loops with a list comprehension.
It is only to be used when you need to create a new list from some other list(s).</p>
<p>If you're looking for some practice, here are a few ideas:</p>
<ul>
<li>Add a list of possible memory sizes to <em>Combining all the elements</em> example and create tuples combined from all three lists.</li>
<li>Take the code from <em>Common elements</em> example, add a new list - <code>princesses_i_like</code>, and try to find the name that appears on all three lists
(you can put in any names you want but if you want to get a result, you have to include Anna or Elsa).</li>
<li>Take the code from <em>Combining elements with the same position</em> example and combine the data only for people older than 20.</li>
</ul>
<p>You can find the solutions in the comments.
If you think of another good use case for list comprehension, feel free to post it in the comments.</p>
<p><sub>Image by Alexandra_Koch from Pixabay</sub></p>
]]></content:encoded></item><item><title><![CDATA[Fluent in Django: Improving your application]]></title><description><![CDATA[This is the second part of Fluent in Django series.
We're going to upgrade the code we created in Part 1.
You can find the finished code from the first part here.

Prerequisites

Python
Basics of Django (Creating a project, Model, View, Templates, Fo...]]></description><link>https://girlthatlovestocode.com/fluent-in-django-improving-your-application</link><guid isPermaLink="true">https://girlthatlovestocode.com/fluent-in-django-improving-your-application</guid><category><![CDATA[Django]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[python projects]]></category><category><![CDATA[framework]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 07 Apr 2021 13:26:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801469636/qnGb5_Tbm.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>This is the second part of <a target="_blank" href="https://girlthatlovestocode.com/series/django">Fluent in Django series</a>.
We're going to upgrade the code we created in <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">Part 1</a>.
You can find the finished code from the first part <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/complete-django-tutorial-part-1">here</a>.</p>
</blockquote>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>Python</li>
<li>Basics of Django (Creating a project, Model, View, Templates, Forms)</li>
<li>Basic understanding of HTML, CSS, and Bootstrap</li>
<li>Finished project from <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/complete-django-tutorial-part-1">Part 1</a></li>
</ul>
<p>If you don't want to do go through the first part, you'll need to get the project we created in Part 1 running.</p>
<blockquote>
<p>How to get the poject from Part 1 running:</p>
<ul>
<li>clone the <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/complete-django-tutorial-part-1">repo</a></li>
<li>create a virtual enviorenment</li>
<li>run <code>pip install -r requirements.txt</code></li>
<li>run <code>python manage.py migrate</code></li>
<li>run <code>python manage.py createsuperuser</code></li>
<li>start the server with <code>python manage.py runserver</code></li>
<li>go to http://127.0.0.1:8000/admin/ and create 4 books - two with a past date and two in the future.</li>
</ul>
<p>If you're struggling with getting the project running, I encourage you to start with <a target="_blank" href="https://girlthatlovestocode.com/fluent-in-django-first-steps">Part 1</a>.</p>
</blockquote>
<h2 id="what-are-you-going-to-learn">What are you going to learn</h2>
<ul>
<li>You'll create an additional field for your form that will allow users to upload their photo when posting their opinion.</li>
<li>Your BookCLub page could look a little better - that's why you're going to add some custom CSS (don't worry, the emphasis is not on CSS but on connecting it with Django).</li>
<li>Why do it by yourself, if someone else has already done it - you'll use two Django packages to make your page better.</li>
<li>You'll learn how to tailor Django admin to your needs.</li>
</ul>
<h2 id="uploading-an-image">Uploading an image</h2>
<p>To enable users to be more personal, you'll add a possibility to upload a photo of them reading the book they're commenting on.
To do this, you'll need a directory that will store the uploaded files, and connect it with Django.</p>
<p>Create a directory called <code>media</code> in the root directory.
Open <code>settings.py</code> and add <code>MEDIA_ROOT</code> and <code>MEDIA_URL</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment">#settings.py</span>

MEDIA_ROOT = BASE_DIR.joinpath(<span class="hljs-string">'media/'</span>)
MEDIA_URL = <span class="hljs-string">'/media/'</span>
</code></pre>
<p><code>MEDIA_ROOT</code> is the absolute path to the directory where the files uploaded by users will be held.
<code>MEDIA_URL</code> is the url from where the images will be served.</p>
<p>To be able to serve user-uploaded media files from MEDIA_ROOT, you need to use <code>django.conf.urls.static</code> in your <code>urls.py</code> file.</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/urls.py</span>
<span class="hljs-keyword">from</span> django.conf.urls.static <span class="hljs-keyword">import</span> static
<span class="hljs-keyword">from</span> tutorial <span class="hljs-keyword">import</span> settings

urlpatterns = [
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
    path(<span class="hljs-string">''</span>, include(<span class="hljs-string">'bookclub.urls'</span>)),
]

<span class="hljs-keyword">if</span> settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
</code></pre>
<p>This method is inefficient and insecure and is only suitable for development. 
That's why we only add the static url pattern if <code>DEBUG</code>  is set to <code>TRUE</code> in your <code>settings.py</code>.
For the production, you'll need <a target="_blank" href="https://docs.djangoproject.com/en/3.1/howto/static-files/deployment/">to do things differently</a>.
We'll cover pushing to production in the latter part of the series.</p>
<p>Django has two model fields that allow user uploads - <code>FileField</code> and <code>ImageField</code>.
<code>ImageField</code> is a specialized version of <code>FileField</code> that uses Pillow to confirm that a file is an image.
Pillow is an image processing library for Python, build on the unmaintained <em>Python Imaging Library</em> (<em>PIL</em>).</p>
<p>Install Pillow with:</p>
<pre><code class="lang-sh">(env)$ python -m pip install Pillow
</code></pre>
<p>Add image field to you model:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Discussion</span>(<span class="hljs-params">models.Model</span>):</span>
    book = models.ForeignKey(<span class="hljs-string">'bookclub.Book'</span>, related_name=<span class="hljs-string">'discussion'</span>, on_delete=models.CASCADE)
    author = models.ForeignKey(<span class="hljs-string">'auth.User'</span>, related_name=<span class="hljs-string">'records'</span>, on_delete=models.CASCADE)
    opinion = models.TextField()
    image = models.ImageField(upload_to=<span class="hljs-string">'images'</span>, blank=<span class="hljs-literal">True</span>)
</code></pre>
<p>The image field has to contain the information where the images will get stored (<code>media/images</code>). We also added a <code>blank=True</code>, which means that the image is not a required field.</p>
<p>Migrate the changes:</p>
<pre><code class="lang-sh">(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
</code></pre>
<p>You need to add an enctype attribute to the form if you want the file to be uploaded correctly:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/book_detail.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">enctype</span>=<span class="hljs-string">"multipart/form-data"</span>&gt;</span> <span class="hljs-comment">&lt;!--this is new--&gt;</span>
    {% csrf_token %}
    {{ discussion_form.as_table }}
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary mt-2"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype">enctype</a> has to be set to <code>multipart/form-data</code> to allow the <code>&lt;input&gt;</code>element to upload file data.</p>
<p>To display the image in the discussion card, you'll have to rearrange the html tags and bootstrap classes, but the basic idea stays the same:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/book_detail.html--&gt;</span>

<span class="hljs-comment">&lt;!--...--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span> <span class="hljs-comment">&lt;!-- this is also new --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span> <span class="hljs-comment">&lt;!-- this is also new --&gt;</span>
                {% for opinion in book.discussion.all %}

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card mb-3"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width: 500px;"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row no-gutters"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
                                {% if opinion.image %}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ opinion.image.url }}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-img"</span>&gt;</span>
                                {% else %}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"http://www.jennybeaumont.com/wp-content/uploads/2015/03/placeholder.gif"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-img"</span>&gt;</span>
                                {% endif %}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-8"</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ opinion.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-text"</span>&gt;</span>{{ opinion.opinion }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                {% empty %}
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-secondary mt-4"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                        There is no opinions yet for this book.
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                {% endfor %}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-comment">&lt;!-- this is also new --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-comment">&lt;!-- this is also new --&gt;</span>
<span class="hljs-comment">&lt;!--...--&gt;</span>
</code></pre>
<p>You can access the uploaded images url with <code>{{ opinion.image.url }}</code>. Because the image is optional (<code>blank=True</code> in our model), you need to check if the image exists with <code>{% if opinion.image %}</code>.
Otherwise, you provide a placeholder.</p>
<h2 id="adding-custom-css">Adding custom CSS</h2>
<p>Things look fine but they could look much better.
Since this is not a CSS tutorial, we're going to change just a few small things, just enough for you to learn how to add static files.</p>
<p>At the bottom of the <code>settings.py</code> file, you can see the static url defined: <code>STATIC_URL = '/static/'</code>.
This tells Django the first part of url your static files can be found.</p>
<blockquote>
<p>As with <code>MEDIA_URL</code>, this is not suitable for production.</p>
</blockquote>
<p>Create a new folder named <code>static</code> inside the <code>bookclub</code> folder.</p>
<pre><code>BookClub
└─── bookclub
     └─── <span class="hljs-built_in">static</span>
</code></pre><p>Django will automatically load static files from any folder named <code>static</code>. </p>
<blockquote>
<p><code>MEDIA_URL</code> and <code>STATIC_URL</code> <strong>must have</strong> different values. So do <code>MEDIA_ROOT</code> and <code>STATIC_ROOT</code>.</p>
</blockquote>
<p>To avoid the collision of two files with the same name inside different apps, organize it the same way as templates - inside the <code>static</code> folder create a folder with the same name as your app.</p>
<p>Create a static folder inside the <code>bookclub</code> app. Inside it, create another folder, named <code>bookclub</code>. 
To make it even more organized, create another folder, called <code>css</code>. 
You want to keep your code neatly organized, so you'll be able to navigate through it even when the project grows big.
Inside the <code>css</code> folder, create a file <code>style.css</code>.</p>
<p>So this is what you have so far:</p>
<pre><code>BookClub
└─── bookclub
     └─── <span class="hljs-built_in">static</span>
         └─── bookclub
              └─── css
                   └─── style.css
</code></pre><p>Now open the <code>style.css</code> and add the following code:</p>
<pre><code class="lang-css"><span class="hljs-comment">/*bookclub.css*/</span>

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">50px</span>;
    <span class="hljs-attribute">background-color</span>: whitesmoke;
}

<span class="hljs-selector-class">.card</span><span class="hljs-selector-class">.mb-3</span><span class="hljs-selector-pseudo">:nth-child(even)</span> {
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>
}

<span class="hljs-selector-class">.card-img</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateY</span>(-<span class="hljs-number">50%</span>);
}

<span class="hljs-selector-tag">form</span> {
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">50px</span>;
}
</code></pre>
<p>This doesn't work yet - you have to connect the <code>css</code> file with the <code>html</code>.
Open <code>base.html</code> and add the tag to load static filed and link to your css file inside the <code>&lt;head&gt;</code>.</p>
<pre><code class="lang-html">{% load static %} <span class="hljs-comment">&lt;!--this is new --&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>BookClub<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% static '/bookclub/css/bookclub.css' %}"</span>&gt;</span> <span class="hljs-comment">&lt;!--this is new --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>You're using the <code>static</code> template tag to build the url for the given relative path (<code>{% static '/css/bookclub.css' %}</code>), but before using it, you need to import it (<code>{% load static %}</code>).</p>
<p>This looks a little better:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801535766/y5U7cSMET.png" alt="with_css.png" /></p>
<blockquote>
<p>If you like CSS, feel free to add a little more pizzaz to your <code>BookClub</code>.</p>
</blockquote>
<h2 id="adding-django-packages">Adding Django packages</h2>
<p>Why write it by yourself if someone else already put a lot of time to create the thing you need?
There are quite some packages for Django that can make your life easier.
You're going to use two of them:</p>
<ul>
<li><a target="_blank" href="https://django-crispy-forms.readthedocs.io/en/latest/">Crispy forms</a> to make the opinion form prettier</li>
<li><a target="_blank" href="https://github.com/django-ckeditor/django-ckeditor">CKEditor</a> so the  book description and opinions can be more than just a plain text</li>
</ul>
<blockquote>
<p>When including Django packages, be careful. Always check on GitHub that the package is well maintained (good: updated in last 3 months / bare minimum: updated in the last year) and that users are content with it (widely used package: at least 1000 star / marginal package: 250 stars).
When it comes to the packages, be like Coco Chanel - less is more.</p>
</blockquote>
<h3 id="crispy-forms">Crispy forms</h3>
<p><code>django-crispy-forms</code> lets you control the rendering behavior of your Django forms in a very elegant and DRY way.
You can make your forms prettier by adding just two simple things to the template.</p>
<p>Install the crispy forms in your shell:</p>
<pre><code class="lang-sh">(env)$ pip install django-crispy-forms
</code></pre>
<p>Add it to <code>INSTALLED_APPS</code>:</p>
<pre><code class="lang-python">INSTALLED_APPS = [
    <span class="hljs-comment"># ...</span>
    <span class="hljs-string">'crispy_forms'</span>,
]
</code></pre>
<blockquote>
<p>Each Django-related package you install, you need to add to <code>INSTALLED_APPS</code> if you want to use it.</p>
</blockquote>
<p>Open <code>book_detail.html</code> and switch the <code>{{ discussion_form.as_table }}</code> part for <code>{{ discussion_form|crispy }}</code>.
For this to work, you need to load <code>crispy_forms_tags</code> prior to that, so the code looks like that:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--book_detail.html--&gt;</span>
{% if discussion_open %}

{% load crispy_forms_tags %} <span class="hljs-comment">&lt;!-- this is new --&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>What are your thoughts on the book?<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>
{% if user.is_authenticated %}
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">enctype</span>=<span class="hljs-string">"multipart/form-data"</span>&gt;</span>
        {% csrf_token %}
        {{ discussion_form|crispy }} <span class="hljs-comment">&lt;!-- this is changed --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary mt-2"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
{% else %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-warning"</span>&gt;</span>Only registered users are allowed to post their opinion.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endif %}
</code></pre>
<p>Refresh the page and the form should look way prettier:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801556169/ZazakPLHR.png" alt="crispy_form.png" /></p>
<h3 id="ckeditor">CKEditor</h3>
<p>Django CKEditor is a package, that adds a WYSIWYG (What-You-See-Is-What-You-Get) editor to your admin fields and your forms.</p>
<p>Install the CKEditor in your shell:</p>
<pre><code class="lang-sh">(env)$ pip install django-ckeditor
</code></pre>
<p>Add it to <code>INSTALLED_APPS</code>:</p>
<pre><code class="lang-python">INSTALLED_APPS = [
    <span class="hljs-comment"># ...</span>
    <span class="hljs-string">'crispy_forms'</span>,
    <span class="hljs-string">'ckeditor'</span>,
]
</code></pre>
<p>Now you have to copy static CKEditor required media resources into the directory given by the STATIC_ROOT setting.
You don't have <code>STATIC_ROOT</code> set yet.</p>
<p>In the bottom of the <code>settings.py</code>, near the <code>STATIC_URL</code>, add</p>
<pre><code class="lang-python"><span class="hljs-comment">#settings.py</span>

STATIC_ROOT = BASE_DIR.joinpath(<span class="hljs-string">'staticfiles'</span>)
</code></pre>
<p>Now run the following command in your shell:</p>
<pre><code class="lang-sh">(env)$ python manage.py collectstatic
</code></pre>
<p>Check the folders in your project. There's an additional folder now, called <code>staticfiles</code> that contains all the static files that exist in your project.</p>
<p>Open <code>models.py</code> and change the <code>description</code> field in the <code>Book</code> class:</p>
<pre><code class="lang-python"><span class="hljs-comment"># models.py </span>
<span class="hljs-keyword">from</span> ckeditor.fields <span class="hljs-keyword">import</span> RichTextField

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>(<span class="hljs-params">models.Model</span>):</span>
<span class="hljs-comment"># ...</span>
description = RichTextField()
<span class="hljs-comment"># ...</span>
</code></pre>
<p>The description is now a <code>RichTextField</code>. <code>RichTextField</code> behaves like a standard <code>TextField</code>, except it includes possibilities to edit the text.
Don't forget to import it.
Migrate the changes with <code>python manage.py makemigrations</code> and <code>python manage.py migrate</code>.</p>
<p>Open one of the books at <code>http://127.0.0.1:8000/admin/bookclub/book/</code> and check it out.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801585473/00fl3byGb.png" alt="rich_field.png" /></p>
<p>Play around a little and edit the text.
If you want the rich text to display properly, you need to add one more thing to the template:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--book_detail.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        {{ book.description|safe}} <span class="hljs-comment">&lt;!-- this is changed --&gt;</span>

        {% if not discussion_open %}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-primary mt-4"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                Read this book by: {{book.read_by}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endif %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>|safe</code> Marks a string as not requiring further HTML escaping prior to output, thus making it render correctly.</p>
<p>Open the book you edited in the browser and now your book description has a little more style:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801601925/xWa1f_dIG.png" alt="rich_field_rendered.png" /></p>
<p>Users are still not able to use the CKEditor in the form.</p>
<p>Change the <code>TextField()</code> to a <code>RichTextField()</code> for <code>opinion</code> filed on the <code>Discussion</code> class, as you did for the <code>Book</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># models.py </span>
<span class="hljs-keyword">from</span> ckeditor.fields <span class="hljs-keyword">import</span> RichTextField

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Discussion</span>(<span class="hljs-params">models.Model</span>):</span>
    book = models.ForeignKey(<span class="hljs-string">'bookclub.Book'</span>, related_name=<span class="hljs-string">'discussion'</span>, on_delete=models.CASCADE)
    author = models.ForeignKey(<span class="hljs-string">'auth.User'</span>, related_name=<span class="hljs-string">'records'</span>, on_delete=models.CASCADE)
    opinion = RichTextField() <span class="hljs-comment"># this is changed</span>
    image = models.ImageField(upload_to=<span class="hljs-string">'images/'</span>, blank=<span class="hljs-literal">True</span>)
</code></pre>
<p>Migrate the change with <code>python manage.py makemigrations</code> and <code>python manage.py migrate</code>.
For the form to show the correct field, you just need to make sure all form media is present.
Add <code>{{ discussion_form.media }}</code> to the <code>book_detail.html</code> prior to the <code>{{ discussion_form|crispy }}</code>.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--book_detail.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">enctype</span>=<span class="hljs-string">"multipart/form-data"</span>&gt;</span>
    {% csrf_token %}
    {{ discussion_form.media }} <span class="hljs-comment">&lt;!-- this is changed --&gt;</span>
    {{ discussion_form|crispy }}
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary mt-2"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>Refresh the page and there it is.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801618278/ctB_8RLen.png" alt="ck_form.png" /></p>
<p>You have to add <code>|safe</code> for the opinions in the <code>book_detail.html</code> to render correctly. </p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--book_detail.html--&gt;</span>
{% for opinion in book.discussion.all %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card mb-3"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width: 500px;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row no-gutters"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
                {% if opinion.image %}
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ opinion.image.url }}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-img"</span>&gt;</span>
                {% else %}
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"http://www.jennybeaumont.com/wp-content/uploads/2015/03/placeholder.gif"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-img"</span>&gt;</span>
                {% endif %}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>{{ opinion.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-text"</span>&gt;</span>{{ opinion.opinion|safe }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-comment">&lt;!-- this is changed --&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% empty %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-secondary mt-4"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
        There is no opinions yet for this book.
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endfor %}
</code></pre>
<p><strong> Don't forget the <code>all_books.html</code>.</strong>
If you go to http://127.0.0.1:8000/, you'll see that text has escaped HTML. As on the book detail page, you need to add <code>|safe</code> - in three places.</p>
<p>For the showcased book:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--all_books.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"jumbotron"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"lead"</span>&gt;</span>What were your thoughts on the latest book?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{previous_books.0.book}}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{previous_books.0.description|truncatewords:150|safe}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-comment">&lt;!-- |safe added --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary btn-lg"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=previous_books.0.pk %}"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span>&gt;</span>See the discussion<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>For the upcoming books:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--all_books.html--&gt;</span>
{% for upcoming_book in upcoming_books %}
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=upcoming_book.pk %}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                {{ upcoming_book.book }}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">small</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-muted"</span>&gt;</span>
                Read by: {{ upcoming_book.read_by }}
            <span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
            {{ upcoming_book.description|safe }} <span class="hljs-comment">&lt;!-- |safe added --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
{% endfor %}
</code></pre>
<p>And for the previous books:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--all_books.html--&gt;</span>

{% for previous_book in previous_books %}
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=previous_book.pk %}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                {{ previous_book.book }}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1 center"</span>&gt;</span>
            {{ previous_book.description|safe }} <span class="hljs-comment">&lt;!-- |safe added --&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
{% endfor %}
</code></pre>
<p>Refresh and everything look good.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801638600/ffO1DyTkT.png" alt="all_books_ck.png" /></p>
<h2 id="pagination">Pagination</h2>
<p>Currently, the user can only see the last 3 previous books and the first three upcoming books. But what if they want to see other books? Maybe they're looking for an idea of what to read next.
Provide them with an option to browse through all the books.</p>
<p>Create an url <code>'book-list'</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/urls.py</span>

urlpatterns = [
    path(<span class="hljs-string">''</span>, views.all_books, name=<span class="hljs-string">"all_books"</span>),
    path(<span class="hljs-string">'book-list'</span>, views.book_list, name=<span class="hljs-string">"book_list"</span>), <span class="hljs-comment"># this is new</span>
    path(<span class="hljs-string">'book/&lt;int:pk&gt;/'</span>, views.book_detail, name=<span class="hljs-string">"book_detail"</span>),
]
</code></pre>
<p>Now for the view:</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/views.py</span>

<span class="hljs-keyword">from</span> django.core.paginator <span class="hljs-keyword">import</span> Paginator


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">book_list</span>(<span class="hljs-params">request</span>):</span>
    books = Book.objects.all()
    paginator = Paginator(books, <span class="hljs-number">5</span>)

    page_number = request.GET.get(<span class="hljs-string">'page'</span>)
    page_books = paginator.get_page(page_number)

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/book_list.html'</span>, {<span class="hljs-string">'page_books'</span>: page_books})
</code></pre>
<ul>
<li>You retrieve all the <code>Book</code> instances, as you did at the beginning of Part 1.</li>
<li>You break them into groups of five with <code>Paginator(books, 5)</code>.</li>
<li>You get the info about on which page the user is from the url with <code>request.GET.get('page')</code>.</li>
<li>You retrieve the books on this page from the <code>Paginator</code> - <code>paginator.get_page(page_number)</code>.</li>
<li>You render only the books from that page to the template</li>
</ul>
<p>Just dumping them in the template is <a target="_blank" href="https://docs.djangoproject.com/en/3.1/topics/pagination/#paginating-a-listview">quite easy</a>, but combining them with <a target="_blank" href="https://getbootstrap.com/docs/4.0/components/pagination/">bootstrap</a> can look complicated.
Inside the <code>templates/bookclub</code> directory, create a <code>book_list.html</code>.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--book_list.html--&gt;</span>

{% extends 'bookclub/base.html' %}

{% block title %}
    All the books
{% endblock %}}

{% block content %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
        {% for book in page_books %}
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=book.pk %}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action mt-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                    {{ book.book }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                {{ book.description|safe }}
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        {% endfor %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-3"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pagination justify-content-center"</span>&gt;</span>
            {% for page in page_books.paginator.page_range %}
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"page-item {% if page == page_books.number %}active{% endif %}"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"page-link"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"?page={{ page }}"</span>&gt;</span>
                    {{ page }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'all_books'%}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"float-right"</span>&gt;</span> Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
{% endblock %}
</code></pre>
<p>The first part is more-or-less copy-pasted from the <code>all_books</code> template, only you're looping through <code>page_books</code>.</p>
<p>As for the part inside the <code>&lt;nav&gt;</code>:</p>
<p>All the html is taken from <a target="_blank" href="https://getbootstrap.com/docs/4.0/components/pagination/#disabled-and-active-states">Bootstrap</a>.
The home link takes the user to the main page.</p>
<p>With Django, you loop through this:</p>
<pre><code class="lang-html">page_books.paginator.page_range
</code></pre>
<p><code>page_books</code> is the queryset you passed from the <code>view</code>.
The <code>paginator</code> in the template is not the same as the one you created in the <code>view</code>. They have the same name, but you could name it differently in the <code>book_list</code> and the <code>paginator</code> in the template would still work (I encourage you to try that, it's always good to see it with your own eyes).
<code>page_range</code> is a range iterator of page numbers (<code>[1, 2, 3, 4]</code>), so the <code>{{ page }}</code> each time shows one of the numbers on the list.
If you'd just like to get the total number of pages, you can use <code>num_pages</code>.</p>
<p>The only other Django thing her is:</p>
<pre><code class="lang-html">{% if page == page_books.number %}active{% endif %}
</code></pre>
<p>With this, you check if the current page iteration (<code>page</code>) is the same as the current page you're on (<code>page_books.number</code>).
If it is, the Bootstrap class <code>active</code> is added.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801658443/heLSttwBT.png" alt="pagination.png" /></p>
<p>Add the link to this page at the bottom of the home page (inside the content block), so you can navigate to the list easily:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--all_books.html--&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_list' %}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary mt-3"</span>&gt;</span>Check all books<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<h2 id="changing-the-admin">Changing the admin</h2>
<p>Admin panel can be very useful. But if you have to open the <code>Book object (3)</code> for the seventh time to check if that's the book you're looking for is not user-friendly.
This is Django, of course, there's a better way.</p>
<p>Django's admin has many hooks for customization. Here you'll use only a few, but if you need something else, you have the documentation for it <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/contrib/admin/">here</a>.</p>
<p>Open <code>admin.py</code> and create a <code>ModelAdmin</code> with all the customization:</p>
<pre><code class="lang-python"><span class="hljs-comment"># ...</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookAdmin</span>(<span class="hljs-params">admin.ModelAdmin</span>):</span>
    list_display = (<span class="hljs-string">'book'</span>, <span class="hljs-string">'read_by'</span>)
    ordering = (<span class="hljs-string">'-read_by'</span>,)
    search_fields = [<span class="hljs-string">'book'</span>]
    fields = ((<span class="hljs-string">'book'</span>, <span class="hljs-string">'read_by'</span>), <span class="hljs-string">'description'</span>)

admin.site.register(Book, BookAdmin)

<span class="hljs-comment"># ...</span>
</code></pre>
<p>So, <code>BookAdmin</code> is basically a 'list' of all the changes you want for your admin.</p>
<ol>
<li><code>list_display</code> determines which fields get displayed in the list of objects</li>
<li><code>ordering</code> determines the default field to order objects by when the page loads. </li>
<li><code>search_fields</code> determines which fields are searchable</li>
<li><code>fields</code> are meant to make simple layout changes. In this case, we force the <code>book</code> and the <code>read_by</code> fields in the same line. This is the only change we made to the single-file admin view</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801675994/j4GT0bhbC.png" alt="changed_admin.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617801685009/dFByZo_7d.png" alt="change_admin_single.png" /></p>
<p>Now it will be much easier to find and edit the correct book.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this part, you made a huge leap from the Django basics.
You added an image field, you used external packages, added custom CSS, learned how to do pagination, and changed admin to your liking.
All of the things we added have a lot more to show, so I invite you to experiment a little.
Play around with the packages, customize admin a little more and if you're not sure what's going on with the code, try to rename or comment out something.
That way, you understand why things are the way they are in no time.</p>
<p>You can find the whole code from Part 2 <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/complete-django-tutorial-part-2">on GitLab</a>.</p>
<blockquote>
<p>Continue with the <a target="_blank" href>Part 3 - COMING SOON</a>, where we'll get the know the Django login, so your members will be able to register to the site.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Roadmap for aspiring web developers]]></title><description><![CDATA[You're thinking about switching your career and become a programmer, but you have no idea where to start?
Are all the buzzwords confusing and you don't know who to ask?
Look no more, here's the post to help.
A lot of information is gathered here. Don...]]></description><link>https://girlthatlovestocode.com/tips-for-newbies</link><guid isPermaLink="true">https://girlthatlovestocode.com/tips-for-newbies</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[beginner]]></category><category><![CDATA[newbie]]></category><category><![CDATA[tips]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Tue, 30 Mar 2021 08:06:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1617089815440/x3Y6mPWT_.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You're thinking about switching your career and become a programmer, but you have no idea where to start?
Are all the buzzwords confusing and you don't know who to ask?
Look no more, here's the post to help.</p>
<p>A lot of information is gathered here. Don't get discouraged if you don't understand everything.
This post is not meant as 'from zero to hero', it is simply meant to be a helpful guide while you navigate your new role.</p>
<h2 id="front-end-vs-back-end">Front-end vs Back-end</h2>
<p>Right at the beginning of your journey, you'll stumble upon a decision - <em>back-end</em> or <em>front-end</em>?
This decision will determine what are you going to learn and what's your job going to be.</p>
<p>Software is usually split into two sides: the presentation side and the data access side.</p>
<p>The presentation side is called front-end and the data access side is called back-end.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617089953453/pce1Q4tq4.png" alt="aspiring_developers.png" /></p>
<blockquote>
<p>A person that combines both, <em>Back-end</em> and <em>Front-end</em> development is considered a <strong>full-stack</strong> developer.</p>
</blockquote>
<h3 id="front-end">Front-end</h3>
<p>Front-end is the part of the web that the user sees.
When you visit a website and you like how the page looks or when you keep scrolling through some images and images keep endlessly popping up, that's front-end work.
Front-end developers also take care of different browsers and devices - it's their merit that you in Firefox and your friend on Safari see the same thing. And although the third friend doesn't see exactly the same page on their phone, they still get the essence of the page, that works well on mobile.</p>
<p>Front-end in its simplicity consists of three things:</p>
<ul>
<li><strong>HTML</strong>: Hypertext Markup Language</li>
<li><strong>CSS</strong>: Cascading Style Sheets</li>
<li><strong>JS</strong>: JavaScript</li>
</ul>
<hr />
<ul>
<li><strong>HTML</strong> is a markup language for documents designed to be displayed in a web browser.
It's the essence of webpages. If anything else would be missing, the pages would be ugly or broken. But if HTML would be missing, there would simply be no webpage.
HTML consists of HTML elements, such as a title, paragraph, link...</li>
</ul>
<blockquote>
<p>Markup language means that when the document is processed for display, the markup language is not shown, and is only used to format the text.</p>
</blockquote>
<ul>
<li><strong>CSS</strong> is a style sheet language used for describing the presentation of the HTML.
Simply put, CSS makes HTML pretty. With it, we assign color, size, and basic behavior to the HTML element.</li>
</ul>
<ul>
<li><strong>JavaScript</strong> is a high-level programming language that enables interactive web pages.
JavaScript is an essential part of web applications and it gets executed by the browser.
It is used for getting the information from client to server, process the information it gets back, and to animate the objects on the page.
As an alternative to it, <em>TypeScript</em> is starting to get attention.</li>
</ul>
<p>After those basics, it gets a little more complicated.
It's a waste of time to do everything by yourself. That's why you get to use libraries and frameworks.
That's a bunch of neatly organized code with additional functionality that you usually get to use for free.</p>
<p>There are a lot of libraries for CSS (Bootstrap, Tailwind CSS...) and for JavaScript (jQuery, React...).
JavaScript frameworks keep popping up and it can be hard to follow all of them. Jokes are going around the existence of so many frameworks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617089970177/hDLV4hg1W.png" alt="jokeJS.png" /></p>
<h3 id="back-end">Back-end</h3>
<p>Back-end handles data storage and business logic. Usually, it is removed physically from the user.
When you register to a website, your data gets sent to the server, where some things are done with your data (eg. your password is hashed, a confirmation mail is sent to you). Or when you watch movies on Netflix, this data is processed in the back-end and it returns 'Similar to watch'.
That's covered by the back-end.</p>
<p>Unlike front-end that consists of three important parts, back-end is usually covered by only one language (as far as you're concerned).
But unlike front-end, where your choices are very limited, back-end has a lot of options.
Different languages are good for different things.</p>
<ul>
<li><p><strong>JavaScript</strong></p>
<p>Yep, JavaScript can be used on both ends.
It's a little confusing, but there are engines that make it possible to run JS on the server-side (eg. Node.js).</p>
<p><strong>Example (Node.js):</strong></p>
<pre><code class="lang-js">  http.createServer(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
    res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'text/plain'</span>});
    res.end(<span class="hljs-string">'Hello World!'</span>);
  }).listen(<span class="hljs-number">8080</span>);
</code></pre>
</li>
<li><p><strong>Java</strong> (Compiled language)</p>
<p>Java is a general-purpose programming language intended to let developers write code once, run anywhere. Unlike other here-mentioned languages, it has to be <em>compiled</em> (translated to a language that the computer understands).</p>
<pre><code class="lang-java">  <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
      ArrayList&lt;String&gt; cars = <span class="hljs-keyword">new</span> ArrayList&lt;String&gt;();
      cars.add(<span class="hljs-string">"Volvo"</span>);
      cars.add(<span class="hljs-string">"BMW"</span>);
      System.out.println(cars);
    }
  }
</code></pre>
</li>
</ul>
<blockquote>
<p> JavaScript and Java are only similar by the name. JavaScript is NOT built on Java.</p>
</blockquote>
<ul>
<li><p><strong>Python</strong> (Scripting language)</p>
<p>Since Python emphasizes code-readability, it's a popular choice for code-newbies. It reads like bad English and it has an interesting trait - it's one of the few languages that treat indentation as significant.</p>
<p><strong>Example (Python):</strong></p>
<pre><code class="lang-python">  fruits = [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"banana"</span>]

  <span class="hljs-keyword">if</span> <span class="hljs-string">"apple"</span> <span class="hljs-keyword">in</span> fruits:
      print(<span class="hljs-string">"Apple is a fruit!"</span>)
</code></pre>
</li>
<li><p><strong>PHP</strong> (Scripting language)</p>
<p>Php is a language that is especially suited to web development. It is widely used - among others, WordPress is built on it.</p>
<p><strong>Example (PHP):</strong></p>
<pre><code class="lang-php">  $cars = <span class="hljs-keyword">array</span>(<span class="hljs-string">"Volvo"</span>,<span class="hljs-string">"BMW"</span>,<span class="hljs-string">"Toyota"</span>);
  var_dump($cars);
</code></pre>
</li>
</ul>
<h2 id="glossary">Glossary</h2>
<p>Here are some common words you may hear or read:</p>
<h4 id="library-and-framework">Library and Framework</h4>
<p>Both libraries and frameworks are reusable code written by someone else. Their purpose is to help you solve common problems.
The difference between them is, who is in control. When using a library, you are in charge of the flow of the application.
When you use a framework, the framework is in charge of the flow.
A framework is like moving in an already built house - you have to buy the furniture that fits and the bathroom is where it is.
A library is like building a house on your own, but with friends' help - a friend that has already built their house lend you the equipment, they gave you the remainder of the tiles and the wall paint they used.</p>
<h4 id="open-source">Open source</h4>
<p>Open source is a term that refers to source code that can people freely modify, study, use and distribute.
Open source is often free of charge, but this is not necessary for the code to be considered open-source.</p>
<p>The open source software you've probably heard of:</p>
<ul>
<li>Linux - (eg. <a target="_blank" href="https://github.com/ubuntu">Ubuntu</a>)</li>
<li><a target="_blank" href="https://code.videolan.org/explore/projects/starred">VLC Media Player</a></li>
<li><a target="_blank" href="https://gitlab.gnome.org/GNOME/gimp">Gimp</a></li>
<li><a target="_blank" href="https://github.com/audacity/audacity">Audacity</a></li>
</ul>
<h4 id="version-control">Version control</h4>
<p>Using version control is similar to playing an arcade video-game. You know when you die and you end up in some check-point before that, not at the beginning of the game?
Version control helps you to not be back at the beginning when you screw up.
It is a system responsible for managing changes in your code.
The most widely used software for it is Git. Git is software for tracking changes in your code.
If you use Git and you screw something up, like in a video-game, you can go back to your 'git check-point'.
It also makes collaboration easier, because you and your colleague won't keep driving over each-others code.</p>
<p>There are some kind of 'storages' where you can store your git versions. It is useful for you to keep track of your code, but also to share interesting projects you created and collaborate on projects someone else created.
The most widely used ones are <a target="_blank" href="https://gitlab.com">GitLab</a> and <a target="_blank" href="https://github.com/">GitHub</a>.</p>
<blockquote>
<p>If you open the open-source code links above - Ubuntu is hosted on GitHub and VLC on GitLab</p>
</blockquote>
<h4 id="command-line">Command line</h4>
<p>Command-line is an abbreviation for Command-line interface (CLI). CLI is a text-based interface that developers use to communicate with computers to accomplish a wider set of tasks.
CLI has a different name on different operating systems (OS):</p>
<ul>
<li>Windows: Command Prompt</li>
<li>Mac OS, Linux: Terminal</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617089985412/n6BSwcveF.png" alt="terminal.png" /></p>
<p>The most basic commands are the same on all the OS, but other commands differ based on the OS you're using (Linux and macOS don't differentiate much, whether Windows commands are almost always different).
Basic commands:</p>
<ul>
<li>change directory:<ul>
<li><strong>cd [directory]</strong> on all OS</li>
</ul>
</li>
<li>create a directory:<ul>
<li><strong>mkdir [name of a new directory]</strong> on all OS</li>
</ul>
</li>
<li>list al directories:<ul>
<li><strong>ls</strong> on Linux and Mac</li>
<li><strong>dir</strong> on Windows</li>
</ul>
</li>
<li>print current local path<ul>
<li><strong>pwd</strong> for Linux and Mad</li>
<li><strong>cd</strong> for Windows</li>
</ul>
</li>
</ul>
<p>Those are tasks that you're also able to do with the mouse, but in programming, you'll be using it to install languages, frameworks, run your code...
You can also run Git commands inside your terminal.</p>
<blockquote>
<p>Try to find the Terminal/Command Prompt on your computer and test some of the commands listed.</p>
</blockquote>
<h4 id="debugging">Debugging</h4>
<p>While coding, you'll make mistakes in a form of typos, business, and coding logic. Those mistakes prevent the program you wrote to run correctly and are called <em>bugs</em>.
The process of finding and fixing those bugs is called <strong>debugging</strong>.
There are a lot of different methods and tools that assist you with it.</p>
<blockquote>
<p>The terms "bug" and "debugging" are popularly attributed to Admiral Grace Hopper in the 1940s. While she was working on a Mark II computer at Harvard University, her associates discovered a moth stuck in a relay and thereby impeding operation, whereupon she remarked that they were "debugging" the system (source: Wikipedia).</p>
</blockquote>
<h4 id="rubber-ducking">Rubber-ducking</h4>
<p>Rubber-ducking is a method of debugging code. It originates from the book The Pragmatic Programmer, where a programmer would carry around a rubber duck and debug their code by explaining the code line-by-line, to the duck.
Although you think to yourself 'But no-one is doing that, right?', you'd be able to find rubber ducks on the desks of a lot of programmers.
Being able to explain your code means you understand it, so it's useful if you get into the habit of doing something like that.</p>
<h2 id="how-to-learn">How to learn</h2>
<p><strong>1. Decide what you are trying to accomplish.</strong></p>
<p>Don't do it just because it's new and everybody is learning it.
Maybe you'll need it to land a new job, maybe you want to create something and that technology is the best tool for the job...</p>
<p><strong>2. Watch an in-depth course.</strong></p>
<p>You can find something on <a target="_blank" href="https://www.udemy.com">Udemy</a>, <a target="_blank" href="https://www.coursera.org/">Coursera</a>, <a target="_blank" href="https://www.freecodecamp.org/">freeCodeCamp</a>...
It's important that the course thoroughly covers the basics, so you gain a good understanding of the technology.</p>
<p><strong>3. Do a tutorial</strong></p>
<p>You can do it during the course or after it. In my experience, there is one leap in the course, you either get it or not.
If you don't, try to do the tutorial in the middle.
If you do, do it after the course ends, so you consolidate your knowledge.</p>
<p><strong>4. Create a simple project</strong></p>
<p>Don't over-complicate it, do something you could find a tutorial for, eg. ToDo list. That way, if you get stuck, it's simple to find a solution to your problem (but do it <strong>on your own</strong>, don't just follow the tutorial).</p>
<p><strong>5. Create an interesting project</strong></p>
<p>That's the reason you went through all the other steps - to create something interesting and something valuable to you.
That's also the step where you learn the most.</p>
<p><strong>* Documentation</strong></p>
<p>Each language and framework you're going to learn includes documentation. That is an online collection of materials that help you navigate through the new technologies.
In it, all the methods and commands that some technologies include, are listed.
There is documentation written well and there is documentation that will make you bang your head against a wall, but you will learn to understand it all.
It can take some time to get used to each new documentation.
When you're learning a new language, try scrolling through the basics and go back to it when you won't know how to achieve what you want with your code.</p>
<h2 id="what-if-i-get-stuck">What if I get stuck</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617089999201/7dYGIWOPO.jpeg" alt="broken_joke.jpeg" /></p>
<p>Inevitably, you'll get stuck. It's nothing wrong with that and it's nothing wrong with asking for help.
You'll have to find a balance between figuring it out on your own and asking for help.
You also have to learn how to ask a question. Generally, your fellow coders will be happy to help.</p>
<p>But: if my daughter is sitting on the couch and wants for me to bring her a glass of water, I'll be mad.
If she comes to me and says:
'Mum, I tried to get myself a glass of water, but I wasn't able to reach the shelf. I tried standing on the chair, but I still couldn't reach it',
I will gladly help her.</p>
<p>See the difference?
Before asking a question, you need to research your problem, you need to be able to articulate it and suggest what you tried and didn't work.</p>
<blockquote>
<p>By the rule of thumb, before asking, spend a half-hour on your problem. Make sure it's not a typo, and make sure the answer to your problem is not one of the first three hits when googling it.</p>
</blockquote>
<h3 id="stack-overflow-so">Stack Overflow (SO)</h3>
<p><a target="_blank" href="https://stackoverflow.com/questions">Stack Overflow</a> is a well-maintained and moderated question-and-answer site for programmers. You will be able to find the solution for most of your problems there.
You don't have to be registered to use it and you'll usually get there by googling your problem.
Registered users are ranked by their contribution and this defines how much they can do on the site.</p>
<ul>
<li>User can ask a question</li>
<li>User can provide an answer to the question</li>
<li>User can vote on the answer (upvote/downvote)</li>
<li>User can comment on the answer</li>
<li>The one who asked a question, can accept one answer</li>
</ul>
<p>SO can be quite intimidating at the beginning, they delete the repeated questions and the question has to be well explained.
Since SO is so big, the probability of you not finding a question similar to yours is very small.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617090022903/JXBKR8C89.png" alt="so.png" /></p>
<p>When looking for an answer:</p>
<ul>
<li>the green checkmark means the answer was accepted as the best one. That's where probably your answer lies, but it's not necessary, so check other answers too.</li>
<li>The number above it means how many people liked the answer. The higher the number, the more likely is to work.</li>
<li>Under it, in smaller letters, are the comments to the answer. They're worth reading because often they provide you some additional information.</li>
<li>Check the date of the answer. Languages are developing fast, frameworks even faster and the answer you found might be outdated.</li>
</ul>
<h3 id="twitter">Twitter</h3>
<p>You probably know Twitter, but maybe you don't know that it has a powerful developer community.
Many programmers share useful tips and tricks, a lot of them are supportive to newbies.
If you want to ask someone for help, look for "DM's open" in their bio. That means you can write direct messages to them and they're usually in a helpful mood as long as you're polite and directly ask a question.</p>
<h3 id="discord">Discord</h3>
<p>Discord is similar to old-school chat-rooms and it's gaining popularity. It's not specifically intended for programmers as SO, but it has developer communities.</p>
<p>Here are some that could be useful for you:</p>
<ul>
<li><a target="_blank" href="https://discord.me/coding">Programmer’s Hangout</a></li>
<li><a target="_blank" href="https://discord.me/codesupport">CodeSupport</a></li>
<li><a target="_blank" href="https://discord.com/invite/code">The coding den</a></li>
</ul>
<h2 id="how-to-google">How to google</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617090038980/5eBZpAkxy.jpeg" alt="google_joke.jpg" /></p>
<p>Googling is a big part of the coding process and it's important to know how to google.</p>
<p>Here are some tips:</p>
<ul>
<li>If you have an error, copy it to google without the specific for your code (eg. name of the file, line number of the error)</li>
<li>Start your search narrow, broaden it if you didn't get what you were looking for (eg. Django settings LOGOUT_REDIRECT_URL -&gt; Django settings )</li>
<li>Remove unnecessary words ('How to', 'and', 'between', '-' ...)</li>
<li>Add the technology for which you are searching (eg. <strong>Python</strong> array, <strong>Bootstrap</strong> container ...)</li>
</ul>
<h2 id="tutorial-hell">Tutorial hell</h2>
<p>There are so many resources (Google, Udemy, blogs...) that enable almost anyone to learn to code by themselves.
But when you're learning on your own, it can be very hard to escape tutorial hell.
Doing tutorials is comfortable, they're easy to follow and you won't get stuck.</p>
<p>Doing a tutorial after tutorial means you won't learn more than the tutorial allows you to.
Tutorials can't teach you to find creative solutions.</p>
<p>There's absolutely nothing wrong with starting with a tutorial.
They're useful to learn the basics and you can rely on the tutorial's code to bail you out if you're stuck.</p>
<p>But you need to get out as soon as possible.
Try altering the project you worked on for the tutorial. Try to create something similar or try to expand it. Only when you're able to do something on your own, you can call yourself a coder.</p>
<h2 id="messages-from-fellow-coders">Messages from fellow coders</h2>
<p>Your fellow developers are rooting for you. Here are some things they would like you to know:</p>
<blockquote>
<p>Things will break and you may break them but the world will not end, ask questions, ask for help, read documentation, be specific with your googling...</p>
<p><a target="_blank" href="https://twitter.com/TyphaneyBdev">@TyphaneyBdev</a></p>
</blockquote>
<hr />
<blockquote>
<p>Listening and communicating skills really important to succeed as a developer. Work on your soft skills as you develop your hard skills. You're going to work with clients and as part of a team. Your soft skills will make the technical part of your job easier.</p>
<p><a target="_blank" href="https://twitter.com/Adriasolutions">@Adriasolutions</a></p>
</blockquote>
<hr />
<blockquote>
<p>Coding is difficult. Ignore false narratives claiming it's easy. It combines problem solving, systems thinking and logic-based creativity. Building skill requires focus, patience and persistence for years.</p>
<p><a target="_blank" href="https://twitter.com/curtiseinsmann">@curtiseinsmann</a></p>
</blockquote>
<hr />
<blockquote>
<p>It's not always about being super technical or complex algorithm... </p>
<p>There is a space for developers with the ability to understand business needs, UX &gt;design and work with other teams.</p>
<p><a target="_blank" href="https://twitter.com/sylvainreiter">@sylvainreiter</a></p>
</blockquote>
<hr />
<blockquote>
<p>It's more important to ask a lot of questions and ask the right questions than to know how to write code (beyond the minimum proficiency of course).</p>
<p><a target="_blank" href="https://twitter.com/miva2">@miva2</a></p>
</blockquote>
<p><sub>Messages were originally posted on <a target="_blank" href="https://twitter.com/GirlLovesToCode/status/1373981352027115520">Twitter</a></sub></p>
<p><sub> Cover image by Pexels from Pixabay </sub></p>
]]></content:encoded></item><item><title><![CDATA[Fluent in Django: First steps]]></title><description><![CDATA[Intro
Knowing a language will only get you so far. If you have to build everything by yourself, you'll never get things done before the deadline.
After you learned a programming language, it's smart to add a framework to your arsenal.
Django is the m...]]></description><link>https://girlthatlovestocode.com/fluent-in-django-first-steps</link><guid isPermaLink="true">https://girlthatlovestocode.com/fluent-in-django-first-steps</guid><category><![CDATA[Django]]></category><category><![CDATA[Python]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[framework]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Mon, 22 Mar 2021 10:12:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407926154/Kgq-5XtMo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="intro">Intro</h2>
<p>Knowing a language will only get you so far. If you have to build everything by yourself, you'll never get things done before the deadline.
After you learned a programming language, it's smart to add a framework to your arsenal.
Django is the most popular full-stack framework for Python.
Once you master it, the production of web applications will be fast and simple.</p>
<p>For your first experience with Django, let's create a BookClub application. User story goes like this. The administrator will post a book with a deadline. 
After the deadline passes, users will be able to discuss the book.
Users will also be able to browse through old and coming-soon book selections.</p>
<h2 id="django">Django</h2>
<blockquote>
<p>The Web framework for perfectionists with deadlines</p>
</blockquote>
<p>Django is an open-source high-level Python framework.
Django framework covers user authentication, security, content administration, and much more.
One of the best traits of Django is that it comes with an out-of-the-box administrative interface.</p>
<p>It also majorly simplify the work with a database. Because if its <em>Models</em> you don't need to work directly with a database. At the same time, you can easily switch one SQL database for the other.</p>
<p>Django emphasizes rapid development - you can have a working, secure and admin-editable website in a matter of hours.</p>
<p>All-in-all, it's a framework worth knowing.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>Basic knowledge of Python</li>
<li>Basic knowledge of HTML</li>
<li>Basic knowledge of CSS Bootstrap (you'll be using it, it's not necessary for you to understand how it works)</li>
</ul>
<h2 id="setup">Setup</h2>
<p>First, create a new directory named BookClub. Open a terminal and navigate to it.
Create and activate a new Python virtual environment:</p>
<pre><code class="lang-sh">$ python3.9 -m venv env
$ <span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<blockquote>
<p>Virtual environment is a tool that helps to keep your project's dependencies separate from dependencies of other projects.
It's like a little computer with its own installation of Python and other packages (Django, requests, Flask, ...) inside your computer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407482404/UMGtOsoIt.png" alt="venv.png" /></p>
</blockquote>
<p>After your virtual environment is active, install Django:</p>
<pre><code class="lang-sh">(env)$ pip install django
</code></pre>
<p>With Django installed, generate a new project:</p>
<pre><code class="lang-sh">(env)$ django-admin startproject tutorial .
</code></pre>
<p><code>django-admin.py</code> is a command-line utility that offers a bunch of administrative tasks.
In this case, with its help, you can create a project named <em>tutorial</em>.
As you can see after you run it, it creates some files that are the core of a Django project.</p>
<p><code>.</code> after the tutorial is an argument that tells Django to add files for a new project to the current directory instead of creating an additional and unnecessary folder for your project.
You have already created a directory for the project previously and you don't need an additional one.</p>
<p>Next, create an app, named <em>bookclub</em>:</p>
<pre><code class="lang-sh">(env)$ django-admin startapp bookclub
</code></pre>
<p>This generates a folder named bookclub, that provides a basic structure for your app.
You'll get to know most of the files in the app throughout this tutorial.</p>
<p>There is always only one project, but you could have multiple apps.
In this tutorial, you'll need only one and it may look like overkill, but it helps you stay well-organized when working on larger projects.</p>
<blockquote>
<p>Project vs. app</p>
<p>Understanding the importance of differing between a project and an app can be confusing at the beginning.</p>
<p>A project is the application you're creating. Apps are its self-sufficient parts. They don't intertwine with each other. In theory, you could copy it from one project and paste it into another without any modification.</p>
<p>Let's say you're creating an application for a library. You'd have a project called <em>Library</em>.
You'd also have apps - one for managing the <em>customers</em> and one for managing the <em>books</em>.
Then you'd get a job creating an online store app that you'd need to register for. You could reuse the <em>customers</em> app from the <em>Library</em> project.</p>
</blockquote>
<p>Going further, open <code>tutorial/settings.py</code> and search for <code>INSTALLED_APPS</code>.
Register the bookclub app at the end:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/settings.py</span>
INSTALLED_APPS = [
    <span class="hljs-comment"># ...</span>
    <span class="hljs-string">'django.contrib.messages'</span>,
    <span class="hljs-string">'django.contrib.staticfiles'</span>,
    <span class="hljs-string">'bookclub'</span>,
]
</code></pre>
<p><code>INSTALLED_APPS</code> is a list of strings designating all applications that are enabled in your project.
If the application is not registered in the <code>INSTALLED_APPS</code>, you won't be able to use it.</p>
<p>Another great trait of Django it's that it rewards you very quickly and lets you know you managed to start a Django app right away.
Run the local server with a command: </p>
<pre><code class="lang-sh">(env)$ python manage.py runserver
</code></pre>
<p>Navigate to: http://127.0.0.1:8000/</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407514593/jxuvVKUsa.png" alt="first_django_look.png" /></p>
<blockquote>
<p>manage.py does the same things as django-admin, but it has DJANGO_SETTINGS_MODULE set to your project's settings.py file.</p>
</blockquote>
<p>This is the structure you have currently:</p>
<pre><code><span class="hljs-selector-tag">BookClub</span>
├── <span class="hljs-selector-tag">manage</span><span class="hljs-selector-class">.py</span>
├── <span class="hljs-selector-tag">tutorial</span>
│   ├── __<span class="hljs-selector-tag">init__</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">settings</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">asgi</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">urls</span><span class="hljs-selector-class">.py</span>
│   └── <span class="hljs-selector-tag">wsgi</span><span class="hljs-selector-class">.py</span>
├── <span class="hljs-selector-tag">bookclub</span>
│   ├── <span class="hljs-selector-tag">admin</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">apps</span><span class="hljs-selector-class">.py</span>
│   ├── __<span class="hljs-selector-tag">init__</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">migrations</span>
│   │   └── __<span class="hljs-selector-tag">init__</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">models</span><span class="hljs-selector-class">.py</span>
│   ├── <span class="hljs-selector-tag">tests</span><span class="hljs-selector-class">.py</span>
│   └── <span class="hljs-selector-tag">views</span><span class="hljs-selector-class">.py</span>
├── <span class="hljs-selector-tag">venv</span>
</code></pre><h2 id="models">Models</h2>
<p>As I mentioned at the beginning, in Django, you don't work directly with the database. You do that with <code>models</code> which are part of Django ORM (Object-relation mapper). Each <em>model</em> represents an entity inside your application - e.g. a book. Models are represented with classes that inherits from <code>models.Model</code>. This gives them the ability to store and retrieve data to/from the database. Each model has defined fields. You can enhance its behavior by adding methods to it. Each instance of your model represents a single row inside the database table. Let's see all of that in practice.</p>
<p>First, create a new file "bookclub/models.py" and create your first model <code>Book</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/models.py</span>
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>(<span class="hljs-params">models.Model</span>):</span>
    book = models.CharField(max_length=<span class="hljs-number">100</span>)
    description = models.TextField()
    read_by = models.DateField()
</code></pre>
<p><code>Book</code> model has 3 fields.
For each field, you have to provide a name and a field type. Some field types require or allow additional parameters.
In this case, those fields are:</p>
<ul>
<li><strong>book</strong> (title) with a maximum of 100 characters</li>
<li><strong>description</strong> is a large text field. The number of characters in it is not limited in Django, but it depends on the database you're using (eg.  for MySQL the limit is 4GB).</li>
<li><strong>read_by</strong> date field</li>
</ul>
<blockquote>
<p>You can see all the field types <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/models/fields/#field-types">here</a>.</p>
</blockquote>
<p>You created a <code>model</code> in <code>models.py</code> but it doesn't exist in the database yet.
When you make a change in your <code>models.py</code> file, you need to communicate that to your database.
You do that with migrations.</p>
<p>Open the <code>migrations</code> folder inside your <code>bookclub</code> directory. There you'll see only one file, <code>__init__.py</code>.
Now run the following command:</p>
<pre><code class="lang-sh">(env)$ python manage.py makemigrations
</code></pre>
<p>Check the folder again and you'll be able to see another file, <code>0001_initial.py</code>.
This is the migration you created. If you open it, you'll see the fields you specified in there.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407531788/5VwWSV8ld.png" alt="migrations.png" /></p>
<p>Now you just need to execute this migration with:</p>
<pre><code class="lang-sh">(env)$ python manage.py migrate
</code></pre>
<blockquote>
<p>Migrations make sure that your database schema matches your models. They add tables, add fields, alter fields, remove tables, ...</p>
</blockquote>
<hr />
<blockquote>
<p>If you're using Django 3.2, you might get a warning upon migration: <code>Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'</code>
You can ignore it for now, but you can read more about it in <a target="_blank" href="https://docs.djangoproject.com/en/dev/releases/3.2/#customizing-type-of-auto-created-primary-keys">Django release notes</a>.</p>
</blockquote>
<h2 id="admin">Admin</h2>
<p>There's an idea of <em>books</em>, but there's no record of any book.
You can add them via the administration panel that Django provides out of the box.
To be able to add new records you need to register the <code>Book</code> model to your admin. You can do that inside "bookclub/admin.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/admin.py</span>
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book

admin.site.register(Book)
</code></pre>
<p>Besides registering a model you also need a user to login into the administration portal. Django provides you a simple way to create a superuser - the one who can do anything. To do that, stop the server with <code>Ctrl + C</code> and run:</p>
<pre><code class="lang-sh">(env)$ python manage.py createsuperuser
</code></pre>
<p>It will prompt you for a username, email address (you don't need to provide one), and password.</p>
<p>Start the server again:</p>
<pre><code class="lang-sh">(env)$ python manage.py runserver
</code></pre>
<p>Navigate to http://127.0.0.1:8000/admin/bookclub/book/ and login with the superuser you created.</p>
<p>Click on <em>Add</em> and add 2 new books of your choosing. I added Harry Potter and Anne of Green Gables.
Set one to the past date and one to the future.
You'll need that further down the road.</p>
<blockquote>
<p>Neat trick: Instead of <code>Save</code>, click <code>Save and add another</code> to save you some clicks. You gotta love Django right?</p>
</blockquote>
<h2 id="show-me-the-books">Show me the books!</h2>
<p>The books are store in a database but you need to present them somehow to your users. So let's create a page that will show those books.</p>
<p>For each page, you need to 3 things:</p>
<ul>
<li><strong>URL</strong>, where your page can be accessed</li>
<li><strong>View</strong> that is a bridge between the model and the template</li>
<li><strong>Template</strong> that will consist of some <code>HTML</code> and dynamic data for the books</li>
</ul>
<h3 id="url">URL</h3>
<p>There's a file <code>urls.py</code> in the project's directory. But as I mentioned before, there can be only one project and multiple apps.
Putting your app's URLs in the project's <code>urls.py</code> can quickly become a tangled mess.
To prevent that, create a new file "bookclub/urls.py" and include it in the main <code>urls.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/urls.py</span>
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include

urlpatterns = [
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
    path(<span class="hljs-string">''</span>, include(<span class="hljs-string">'bookclub.urls'</span>)),
]
</code></pre>
<blockquote>
<p>Don't forget to import <code>include</code></p>
</blockquote>
<p>Now open the newly created <code>bookclub/urls.py</code> file and write the following in it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/urls.py</span>
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> . <span class="hljs-keyword">import</span> views

urlpatterns = [
    path(<span class="hljs-string">''</span>, views.all_books, name=<span class="hljs-string">"all_books"</span>),
]
</code></pre>
<p>Url patterns define url paths that exist inside your application. For example, <em>/books</em>. At this point, you're building the first page, home page, so you defined your path as '' - that translates to <em>/</em>. You'll be able to access this page at <a target="_blank" href="http://localhost:8000">http://localhost:8000</a>. The next parameter of the path is a view function. View function will receive the request from a browser and return an HTML page that will be shown in a browser. The <code>name</code> attribute is optional, but by assigning it, you will be able to reference it in the view methods and templates.
Assigning a <code>name</code> also means that you can easily change the path, without the need for a change everywhere else in the project.
You might have noticed that you're importing something that doesn't exist? It's view function <code>all_books</code>. Let's proceed and create it.</p>
<h2 id="view">View</h2>
<p>View function is a Python function that takes a Web request and returns a Web response.
In it, you can write the logic you need to return the correct response.</p>
<p>By convention, the view functions are written in a file <code>views.py</code>.</p>
<p>Many of your views will return something from your models combined with a template, but not necessarily.
You could also return a simple string with some HTML if you'd have some reason for it.</p>
<p>Open <code>bookclub/views.py</code> and add a <code>all_books</code> view to it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/views.py</span>
<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">all_books</span>(<span class="hljs-params">request</span>):</span>
    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/all_books.html'</span>)
</code></pre>
<p>The render method is Django's method that combines the given template with the context dictionary and returns a <code>HttpResponse</code> with rendered text.</p>
<h2 id="lessa-nametemplategreaterlessagreatertemplate"><a></a>Template</h2>
<p>The <code>all_books.html</code> file you passed to the render method doesn't exist yet. By default, Django loads templates from all <em>templates</em> directories inside your apps. To make templates accessible to Django you should create a new folder "bookclub/templates". If you would put <em>all_books.html</em> inside that folder you could call render like this <code>return render(request, 'bookclub/all_books.html')</code>. To avoid the name collision it's suggested to create another folder inside "bookclub/templates". This creates <em>namespace</em> for your templates. This way you can have <em>index.html</em> inside app <em>bookclub</em>, app <em>users</em>, etc.</p>
<pre><code><span class="hljs-selector-tag">BookClub</span>
    └── <span class="hljs-selector-tag">bookclub</span>
        └── <span class="hljs-selector-tag">templates</span>
            └── <span class="hljs-selector-tag">bookclub</span>
                └── <span class="hljs-selector-tag">all_books</span><span class="hljs-selector-class">.html</span>
</code></pre><p>So let's create a new folder "bookclub/templates/bookclub" and add a new file <em>all_books.html</em> inside:</p>
<pre><code class="lang-html">Something
</code></pre>
<p>Check your application in a browser at <a target="_blank" href="http://localhost:8000">http://localhost:8000</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407548257/-z1KMLiki.png" alt="first_look.png" /></p>
<blockquote>
<p>If you have an error, stop the server by pressing <code>Ctrl+C</code> in your command line and start it again with <code>python manage.py runserver</code>.</p>
</blockquote>
<h2 id="dynamic-data">Dynamic data</h2>
<p>You need a page that will show books stored in the database. Let's improve your view function inside "bookclub/views.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/views.py</span>
<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> bookclub.models <span class="hljs-keyword">import</span> Book

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">all_books</span>(<span class="hljs-params">request</span>):</span>
    books = Book.objects.all()

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/all_books.html'</span>, {<span class="hljs-string">'books'</span>: books})
</code></pre>
<p>You retrieved all records of the <code>Book</code> model with <code>Book.objects.all()</code> and passed it to the template as a dictionary <code>{'books': books}</code>.</p>
<blockquote>
<p>Key <em>books</em> and variable name <em>books</em> don't need to be the same</p>
</blockquote>
<p>Edit <em>all_books.html</em> to show books:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/all_books.html--&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>BookClub<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
{{ books }}
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It's not pretty, but it's something!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407564203/qLTB-wVo0.png" alt="books_showing.png" /></p>
<h2 id="extending-the-template">Extending the template</h2>
<p>Eventually, you'll add more templates and you don't want to keep adding the basic <code>html</code> tags and style/js imports to every file.
To solve that problem, Django offers a template extending.
Template extending makes it possible to use the same piece of <code>HTML</code> in more than one place.
This is useful for basic HTML layout, for navigation, for imports...</p>
<p>You'll create a base file, that will cover the basic layout of <code>HTML</code> and the imports, so you won't need to do that more than once.
Inside the body tags, you'll create a space for the content.</p>
<p>Inside the "bookclub/templates" folder, create a new file <em>base.html</em>:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/base.html--&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>BookClub<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    {% block content %}
    {% endblock %}
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It's the same as <em>all_books.html</em> with one minor change - <code>{{ books }}</code> is replaced with <code>{% block content %} {% endblock %}</code>.</p>
<p>Move to the <code>all_books.html</code> file and delete everything except the <code>{{ books }}</code> part:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/all_books.html--&gt;</span>
{% extends 'bookclub/base.html' %}

{% block content %}
{{ books }}
{% endblock %}}
</code></pre>
<p>You don't need the rest of the code, <code>base.html</code> covers it.</p>
<p>At the top of the file, you specified which file this template is extending -&gt; <code>base.html</code>.
The <code>{{ books }}</code> variable is wrapped with a <code>{% block content %}</code> tag. That informs Django that this part of the template fits in the <code>content</code> block.</p>
<p>That's because you could have multiple blocks inside one template.
In fact, add another block.</p>
<blockquote>
<p><strong>Variables vs. Tags</strong></p>
<p><strong>Variables</strong> are surrounded by <code>{{ }}</code>. They output values from the context (as set in the view).</p>
<p><strong>Tags</strong> are surrounded by <code>{% %}</code>. They provide arbitrary logic in the rendering process. They enclose if statements and for loops.</p>
</blockquote>
<p>In the <code>base.html</code> add a block <em>title</em>.</p>
<pre><code class="lang-html">{% block title %}{% endblock %}

{% block content %}
{% endblock %}&gt;
</code></pre>
<p>Now you added an additional block that can be filled, named <code>title</code>.
You can now provide a different title for each of your pages.
Add a block <code>title</code> to your <code>all_books.html</code> file.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/bookclub/all_books.html--&gt;</span>
{% extends 'bookclub/base.html' %}

{% block title %}
All the books
{% endblock %}}

{% block content %}
{{ books }}
{% endblock %}}
</code></pre>
<p>Refresh the page and you can see the added content.</p>
<h2 id="adding-bootstrap">Adding Bootstrap</h2>
<p>Plain HTML is fine for showing information but users love beautiful applications. So let's add the Bootstrap. Edit your "bookclub/templates/bookclub/base.html":</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/base.html--&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>BookClub<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-5 mb-5"</span>&gt;</span>{% block title %} {% endblock %}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        {% block content %}
        {% endblock %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.5.1.slim.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>At the top of the file, you've imported Bootstrap from CDN. At the bottom, you've imported jQuery and Boortsratp's Javascript.
As you can see, now everything inside the body is wrapped inside the <code>.container</code> and <code>h1</code> has a large margin at the top and the bottom (<code>mt-5 mb-5</code>).</p>
<p>Until now, you just kind-of dumped the books data.</p>
<p>Let's list those books and add some style. Edit your "bookclub/templates/bookclub/all_books.html":</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/all_books.html--&gt;</span>
{% extends 'bookclub/base.html' %}

{% block title %}
All the books
{% endblock %}}

{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
    {% for book in books %}
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item-heading"</span>&gt;</span>
            {{ book.book }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item-text"</span>&gt;</span>
            {{ book.description }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    {% endfor %}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endblock %}}
</code></pre>
<p>That looks like a lot is going on in there, but it's not really that complicated.
Instead of <code>{{ books }}</code>, you now display each field for each book separately.
You loop through all the books one by one with <code>{% for book in books %}</code>. You close the forloop with <code>{% endfor %}</code>.
You access a single field of the current book with <code>{{ book.fieldname }}</code>.
All the <code>div</code>s and classes are just some <code>HTML</code> tags and some Bootstrap to make things look pretty.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407581824/I3_CaQH7k.png" alt="added_bootstrap.png" /></p>
<blockquote>
<p>Check the details about the list-group you used for styling the books <a target="_blank" href="https://getbootstrap.com/docs/4.6/components/list-group/#custom-content">here</a>.</p>
</blockquote>
<h2 id="group-books">Group books</h2>
<p>The upcoming and previous books should be displayed separately.
To do that, you have to pass two separate variables to the template.</p>
<h3 id="view">View</h3>
<p>Change the view to provide two variables instead of one. One that will show only the upcoming books and another to show some of the previously read books. Edit your "bookclub/views.py":</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> date
<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render

<span class="hljs-keyword">from</span> bookclub.models <span class="hljs-keyword">import</span> Book


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">all_books</span>(<span class="hljs-params">request</span>):</span>
    upcoming_books = Book.objects.filter(read_by__gte=date.today()).order_by(<span class="hljs-string">'read_by'</span>)[:<span class="hljs-number">3</span>]
    previous_books = Book.objects.filter(read_by__lt=date.today()).order_by(<span class="hljs-string">'-read_by'</span>)[:<span class="hljs-number">3</span>]

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/all_books.html'</span>, {<span class="hljs-string">'upcoming_books'</span>: upcoming_books, <span class="hljs-string">'previous_books'</span>: previous_books})
</code></pre>
<p>There is a lot new going on in here, let's examine it in detail:</p>
<ul>
<li>Instead of <code>.all()</code> method, you're now calling <code>.filter</code>. This simply means you're not querying all the books, but just the ones matching the query.</li>
<li><code>read_by</code> is referring to the model field, <code>__gte</code> means <em>greater or equal to</em> and <code>__lt</code> means less than.</li>
<li>In both cases, you're comparing <code>read_by</code> date to today's date.</li>
<li>After you got the filtered results, you're sorting them by <code>read_by</code> date.<ul>
<li><code>read_by</code> sorts from today's date to the date furthest in the future ('smallest' date -&gt; 'biggest' date)</li>
<li><code>-read_by</code> sorts it the other way around - from yesterday's date to the date furthest in the past ('biggest' date -&gt; 'smallest' date)</li>
</ul>
</li>
<li><code>[:3]</code> shows the first 3 results.</li>
<li>Instead of <code>books</code>, you now return values for both of your queries - <code>upcoming_books</code> and <code>previous_books</code>.</li>
</ul>
<blockquote>
<p>Create additional 5 books - 2 in the past, 2 in the future, and one with today's date.</p>
</blockquote>
<h3 id="template">Template</h3>
<p>If you want to show both variables in the template, basic logic of it would go like this:</p>
<pre><code class="lang-html">{% for upcoming_book in upcoming_books %}
{{ upcoming_book.book }}
{{ upcoming_book.read_by }}
{{ upcoming_book.description }}
{% endfor %}

{% for previous_book in previous_books %}
{{ previous_book.book }}
{{ previous_book.read_by }}
{{ previous_book.description }}
{% endfor %}
</code></pre>
<p>But that would produce a very ugly result.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407598934/Xi6v2HdVt.png" alt="ugly_result.png" /></p>
<p>Resort to Bootstrap to make it pretty. </p>
<p>Besides the <a target="_blank" href="https://getbootstrap.com/docs/4.6/components/list-group/#custom-content">list group</a> for the books, use <a target="_blank" href="https://getbootstrap.com/docs/4.6/components/navs/#javascript-behavior">tabs</a> to enable the user to switch between previous and upcoming books effortlessly. Edit your "bookclub/templates/bookclub/all_books.html":</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/bookclub/all_books.html--&gt;</span>
{% extends 'bookclub/base.html' %}

{% block title %}
All the books
{% endblock %}}

{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav nav-tabs mb-3"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"allBooks"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tablist"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"presentation"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link active"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"home-tab"</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#upcoming"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"upcoming"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"true"</span>&gt;</span>Upcoming Books<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"presentation"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"profile-tab"</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#previous"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"previous"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"false"</span>&gt;</span>Previous Books<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab-content"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"allBooksContent"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab-pane fade show active"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"upcoming"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"upcoming-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
            {% for upcoming_book in upcoming_books %}
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                        {{ upcoming_book.book }}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">small</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-muted"</span>&gt;</span>
                        Read by: {{ upcoming_book.read_by }}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                    {{ upcoming_book.description }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab-pane fade"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"previous"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"previous-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
            {% for previous_book in previous_books %}
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                        {{ previous_book.book }}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                    {{ previous_book.description }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endblock %}}
</code></pre>
<p>This is much prettier, right?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407619292/-jC1FHjNtc5.png" alt="upcoming_books.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407631182/PcwYzki4i.png" alt="previous_books.png" /></p>
<p>As you can see, today's book is showing in the <strong>upcoming books</strong> tab, because you used <code>__gte</code> in the query.
If you'd use <code>__gt</code>, the book with today's date would not show.
If you've created 4 <em>upcoming</em> books (3 with future dates and today's one), you can also see that the last one is not showing.
That's because you're showing only the 3 books closest to today's date.</p>
<h2 id="single-book-view">Single book view</h2>
<p>The business model predicts that users will be able to comment on the book.
This means you need to have a page for a single book.</p>
<p>First, add the url in "bookclub/urls.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/urls.py</span>
<span class="hljs-comment"># imports here</span>

urlpatterns = [
    path(<span class="hljs-string">''</span>, views.all_books, name=<span class="hljs-string">"all_books"</span>),
    path(<span class="hljs-string">'book/&lt;int:pk&gt;/'</span>, views.book_detail, name=<span class="hljs-string">"book_detail"</span>),
]
</code></pre>
<p>Every single book will have an url like this <code>http://127.0.0.1:8000/book/1/</code>.
The <code>&lt;int:pk&gt;</code> part means that in this part of url an integer is expected.
With Django's help, you will be able to extract it and match it with a book's id in the view. Add a new view for book details to "bookclub/views.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/views.py</span>

<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> date
<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render, get_object_or_404
<span class="hljs-keyword">from</span> bookclub.models <span class="hljs-keyword">import</span> Book

<span class="hljs-comment"># all_books view here</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">book_detail</span>(<span class="hljs-params">request, pk</span>):</span>
    book = get_object_or_404(Book, pk=pk)

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/book_detail.html'</span>, {<span class="hljs-string">'book'</span>: book})
</code></pre>
<p><code>get_object_or_404</code> calls a <code>get()</code> method on the given <code>Model</code> and it raises <code>404</code> error when an expected object is not found.
The <code>pk</code> key from the url is passed to the view as a parameter and you pass it to the <code>get_object_or_404</code>, so it returns the book with the correct id.</p>
<blockquote>
<p><em>pk</em> is the abbreviation for primary key of the object. In this case, it's an ID of the row in a database.</p>
</blockquote>
<p>You pass the book you get back in the context dictionary to a template <code>book_detail.html</code> that you have yet to create.</p>
<p>Add a new file named <em>book_detail.html</em> inside "bookclub/templates/bookclub" folder:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/book_detail.html--&gt;</span>

{% extends 'bookclub/base.html' %}

{% block title %}
{{ book.book }}
{% endblock %}}

{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        {{ book.description}}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endblock %}
</code></pre>
<p>Part of this template is very similar to the previous one:</p>
<ul>
<li>you extended the <code>base.html</code></li>
<li>you have a block <code>title</code> and block <code>content</code></li>
<li>you have divs with some Bootstrap classes</li>
</ul>
<p>The difference is that you didn't hardcode the title of the page, but provided the title of a book in it.
In the body of the card, the book description is displayed.</p>
<h2 id="link-between-the-pages">Link between the pages</h2>
<p>If you navigate to http://127.0.0.1:8000/ and you try to click on the book, you'll find out that although the single page for the book exists, you can't navigate there via links.
To add that possibility, open <code>all_books.html</code>.
Because you loop through books two times, you need to change the <code>HTML</code> in the two places.</p>
<pre><code class="lang-html">{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav nav-tabs mb-3"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"allBooks"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tablist"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"presentation"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link active"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"home-tab"</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#upcoming"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"upcoming"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"true"</span>&gt;</span>Upcoming Books<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"presentation"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"profile-tab"</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#previous"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"previous"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"false"</span>&gt;</span>Previous Books<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab-content"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"allBooksContent"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab-pane fade show active"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"upcoming"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"upcoming-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
            {% for upcoming_book in upcoming_books %}
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=upcoming_book.pk %}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action"</span>&gt;</span> <span class="hljs-comment">&lt;!--          this is new--&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                        {{ upcoming_book.book }}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">small</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-muted"</span>&gt;</span>
                        Read by: {{ upcoming_book.read_by }}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                    {{ upcoming_book.description }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab-pane fade"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"previous"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"previous-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
            {% for previous_book in previous_books %}
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=previous_book.pk %}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-group-item list-group-item-action"</span>&gt;</span> <span class="hljs-comment">&lt;!--          this is new--&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex w-100 justify-content-between"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                        {{ previous_book.book }}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
                    {{ previous_book.description }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endblock %}}
</code></pre>
<p>With <code>url</code>, you're ordering Django to create an url.
Url will be composed as follows:</p>
<ul>
<li><code>book_detail</code> refers to the name you gave to your URL pattern inside the <em>urls.py</em> (<code>book/&lt;int:pk&gt;/</code>)</li>
<li>the private key (<code>upcoming_book.pk</code>) for the current book is passed as a parameter, so the <code>&lt;int:pk&gt;</code> will be correctly filled.</li>
</ul>
<p>Refresh the <code>http://127.0.0.1:8000/</code> page.
Now if you click on one of the books, you should get to the single page for said book.</p>
<p>But you can't navigate back.</p>
<p>Edit your <code>bookclub/templates/bookclub/book_detail.html</code> to add a back button:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--book_detail.html--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        {{ book.description}}

        {% if not discussion_open %}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-primary mt-4"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
            Read this book by: {{book.read_by}}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endif %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'all_books'%}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"float-right"</span>&gt;</span>Back to all books<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> <span class="hljs-comment">&lt;!--          this is new--&gt;</span>
</code></pre>
<p>As you can see, the url creation is very similar to the previous one, the only difference is that you didn't need to provide a <code>pk</code> parameter.
Now you can navigate between a single book and the list.</p>
<h2 id="add-some-logic-to-the-view">Add some logic to the view</h2>
<p>At this point, you just got some data from the <code>Book</code> model and you passed it to the template.
You can do more than that in a <code>view</code> - you can do something with the data you retrieved and pass that to the template.</p>
<p>Just seeing a book description is not very useful. You have a Wikipedia page for that.
You want people to be able to discuss the book, but only if the deadline hasn't already passed.
This means the template will change a little, based on the date of the deadline -
upcoming books will show the deadline and previous books will have the discussion open.</p>
<p>To know what to show for the book in question, you need to pass some sort of a flag from the <code>book_detail</code> view inside "bookclub/views.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/views.py</span>
<span class="hljs-comment"># all_ books view and other imports</span>

<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render, get_object_or_404

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">book_detail</span>(<span class="hljs-params">request, pk</span>):</span>
    book = get_object_or_404(Book, pk=pk)
    discussion_open = <span class="hljs-literal">False</span>

    <span class="hljs-keyword">if</span> book.read_by &lt;= date.today():
        discussion_open = <span class="hljs-literal">True</span>

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/book_detail.html'</span>, {<span class="hljs-string">'book'</span>: book, <span class="hljs-string">'discussion_open'</span>: discussion_open})
</code></pre>
<p>Passing a flag is as simple as that. You accessed a field on the retrieved book and if the date has already passed (or is today), the <code>discussion_open</code> is set to true.</p>
<p>Now you use that flag in the template "bookclub/templates/bookclub/book_detail.html":</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/book_detail.html--&gt;</span>
<span class="hljs-comment">&lt;!-- extends and block title here--&gt;</span>

{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        {{ book.description}}

        {% if not discussion_open %}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-primary mt-4"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
            Read this book by: {{book.read_by}}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endif %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% if discussion_open %}
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"success"</span>&gt;</span> Discussion is opened. <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
{% else %}
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert"</span>&gt;</span> Discussion is not enabled yet for this book.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
{% endif %}
{% endblock %}
</code></pre>
<p>You added 2 <code>if blocks</code>. If the discussion_open is false, you display the deadline inside the card.
At the bottom, you display two different notices, based on if the deadline has already passed or not.</p>
<p>As for the books whose deadline has not passed yet, you covered everything.
As for the books that should have discussion enabled, this is the next thing you're going to do.</p>
<h2 id="discussion-model">Discussion model</h2>
<p>You'll need another model for the discussion. Each instance of the <code>Discussion</code> model will be connected to one of the Book instances and one of the User instances via foreign keys.</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/models.py</span>

<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>(<span class="hljs-params">models.Model</span>):</span>
<span class="hljs-comment"># ...</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Discussion</span>(<span class="hljs-params">models.Model</span>):</span>
    book = models.ForeignKey(<span class="hljs-string">'bookclub.Book'</span>, related_name=<span class="hljs-string">'discussion'</span>, on_delete=models.CASCADE)
    author = models.ForeignKey(<span class="hljs-string">'auth.User'</span>, related_name=<span class="hljs-string">'records'</span>, on_delete=models.CASCADE)
    opinion = models.TextField()
</code></pre>
<p>You have the opinion (<code>TextField</code>) for the Discussion instance and two foreign keys we already mentioned - the book for which comment is intended and the author of the comment.</p>
<p><code>ForeignKey</code> is a field that represents many-to-one relationships. 
In this case, you're connecting the <code>Discussion</code> model with  <code>Book</code> model you created and with Django's out-of-the-box <code>User</code> model.</p>
<p>The first positional argument in the <code>ForeignKey</code> class is the class to which the model is related (in our case <code>bookclub.Book</code> and <code>auth.User</code>) and it is required. </p>
<blockquote>
<p>You can access models in another application by specifying the name of the application first (<code>auth</code>); the second part is the name of the model (<code>.User</code>).</p>
</blockquote>
<p><code>on_delete</code> specifies what happens with the instances of the current model if the model accessed with <code>ForeignKey</code> is deleted (eg. if you delete the book, you'd want all the comments on a said book to be deleted too. That's what you achieve by <code>models.CASCADE</code>).</p>
<p><code>related_name</code> is a name by which you can access the <code>Discussion</code> instances from the related Model (<code>Book</code> or <code>User</code>). Later you'll be able to see that we can access all the discussion for a book with <code>book.discussion</code>. <code>.discussion</code> being the related name we just assigned.</p>
<p>You made a change to your models, but your database has not been notified yet.</p>
<p>Run the following commands in your terminal:</p>
<pre><code class="lang-sh">(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
</code></pre>
<h2 id="django-forms">Django forms</h2>
<p>Django makes it easy to handle forms. It prepares and restructures data to make it ready for rendering, creates HTML forms, receives and processes submitted data from the client.
You'll create a form that will correspond to the <code>Discussion</code> model. This means you'll define a <code>ModelForm</code>.</p>
<p>Define a <code>DiscussionForm</code> in "bookclub/forms.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/forms.py</span>
<span class="hljs-keyword">from</span> django <span class="hljs-keyword">import</span> forms
<span class="hljs-keyword">from</span> bookclub.models <span class="hljs-keyword">import</span> Discussion

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DiscussionForm</span>(<span class="hljs-params">forms.ModelForm</span>):</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Discussion
        fields = (<span class="hljs-string">'opinion'</span>,)
</code></pre>
<p>In the <code>class Meta</code>, you defined that you're going to connect the form with the <code>Discussion</code> model and the only field you have is the <code>opinion</code>.</p>
<blockquote>
<p><code>fields</code> have to be passed as a tuple. That means that even if you're passing only one field, the <code>()</code> and the <code>,</code> are necessary.</p>
</blockquote>
<p>You need to process the form you created inside the <code>book_detail</code> view in "bookclub/views.py": </p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/views.py</span>
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> date
<span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render, get_object_or_404, redirect
<span class="hljs-keyword">from</span> django.http <span class="hljs-keyword">import</span> HttpResponseForbidden
<span class="hljs-keyword">from</span> bookclub.forms <span class="hljs-keyword">import</span> DiscussionForm
<span class="hljs-keyword">from</span> bookclub.models <span class="hljs-keyword">import</span> Book

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">book_detail</span>(<span class="hljs-params">request, pk</span>):</span>
    book = get_object_or_404(Book, pk=pk)
    discussion_form = DiscussionForm()
    discussion_open = <span class="hljs-literal">False</span>

    <span class="hljs-keyword">if</span> book.read_by &lt;= date.today():
        discussion_open = <span class="hljs-literal">True</span>

    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">"POST"</span>:
        form = DiscussionForm(request.POST)

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> request.user.is_anonymous:

            <span class="hljs-keyword">if</span> form.is_valid():
                opinion = form.save(commit=<span class="hljs-literal">False</span>)
                opinion.author = request.user
                opinion.book = book
                opinion.save()

                <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">'book_detail'</span>, pk=book.pk)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> HttpResponseForbidden(<span class="hljs-string">"Forbidden"</span>)

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'bookclub/book_detail.html'</span>, {<span class="hljs-string">'book'</span>: book, <span class="hljs-string">'discussion_open'</span>: discussion_open, <span class="hljs-string">'discussion_form'</span>: discussion_form})
</code></pre>
<p>You added a new instance of <code>DiscussionForm</code> in the <code>book_detail</code> view, and you passed it to the template.
That's all that is needed for displaying it.</p>
<p>But when the user submits it, you need to do a little more:</p>
<ul>
<li>you create an instance of the <code>DiscussionForm</code> and fill it with the data retrieved from the request</li>
<li>you check if the user is anonymous and if they are, you return <code>HttpResponseForbidden("Forbidden")</code>. That way, you prevent unauthenticated users to post comments.</li>
<li>you use built-in form validation to check if the form is valid</li>
<li><code>commit=False</code> means you don't want to save the form yet - first you need to add the data that was not supplied by the user</li>
<li>You can't allow the user to select the author or the discussion post on their own, you add it while processing the form:<ul>
<li>author is the person that submitted the request</li>
<li>since the form is displayed on the page for the single book, you know exactly for which book it was submitted. You pass the book you retrieved already to display it to the form.</li>
</ul>
</li>
<li>you save the form manually since you prevented it from saving it in the first place</li>
</ul>
<p>The last thing to do is to display the form in the template "bookclub/templates/bookclub/book_detail.html":</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/book_detail.html--&gt;</span>
<span class="hljs-comment">&lt;!--...--&gt;</span>
<span class="hljs-comment">&lt;!--&lt;h2 class="mt-5 mb-3"&gt;Discussion&lt;/h2&gt;--&gt;</span>
<span class="hljs-comment">&lt;!--{% if discussion_open %}--&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>What are your thoughts on the book?<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>
    {% if user.is_authenticated %}
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>&gt;</span>
        {% csrf_token %}
        {{ discussion_form.as_table }}
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary mt-2"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    {% else %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-warning"</span>&gt;</span>Only registered users are allowed to post their opinion.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endif %}

<span class="hljs-comment">&lt;!--{% else %}--&gt;</span>
<span class="hljs-comment">&lt;!--...--&gt;</span>
</code></pre>
<p>Since posting a comment is allowed only to registered users, you check if the user is logged in with <code>{% if user.is_authenticated %}</code>.</p>
<blockquote>
<p>From here on, we're working with a logged-in user. If you're able to see the "Only registered users are allowed to post their opinion.", navigate to http://127.0.0.1:8000/admin/login/ and login with your superuser.</p>
</blockquote>
<p>Using the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/csrf/">csrf_token</a> provides protection against Cross Site Request Forgeries.</p>
<p>You can display the form you created in <a target="_blank" href="https://docs.djangoproject.com/en/3.1/topics/forms/#working-with-form-templates">many ways</a>. Here you simply rendered the whole form as a table.
You also could display just the one field without the label, it would be prettier, but would mean unnecessary complications.</p>
<blockquote>
<p>The form looks less than ideal, but we're changing it right at the beginning of the <a target="_blank" href>second part - COMING SOON</a>, don't worry.</p>
</blockquote>
<h2 id="displaying-the-discussion">Displaying the discussion</h2>
<p>You should now be able to post your opinion via the form, but you can't check that.
You don't see it nor on the single book page, nor in the admin panel.</p>
<p>First, make it visible in the admin panel.
Edit "bookclub/admin.py" and add the <code>Disccussion</code> the same way you added the <code>Book</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># bookclub/admin.py</span>

<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book, Discussion

admin.site.register(Book)
admin.site.register(Discussion)
</code></pre>
<p>If you open the <code>http://127.0.0.1:8000/admin/</code>, you'll be able to see the <code>Discussions</code> on the left side.
You can edit them or add them here if necessary.</p>
<p>You may expect that you need to get all the values from the <code>Discussion</code> in the <code>view</code> first.
But that's the magic of Django - you can simply access it via the <code>Book</code> in the template.
Add the folowing code under the form inside the <code>{% if discussion_open %}</code> in the <code>bookclub/templates/bookclub/book_detail.html</code>:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--templates/bookclub/book_detail.html--&gt;</span>
<span class="hljs-comment">&lt;!--    ... --&gt;</span>
<span class="hljs-comment">&lt;!--    {% else %}--&gt;</span>
<span class="hljs-comment">&lt;!--    &lt;div class="alert alert-warning"&gt;Only registered users are allowed to post their opinion.&lt;/div&gt;--&gt;</span>
<span class="hljs-comment">&lt;!--    {% endif %}--&gt;</span>

    {% for opinion in book.discussion.all %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card mt-4"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-header"</span>&gt;</span>
        {{ opinion.author }}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-body"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-text"</span>&gt;</span>{{ opinion.opinion }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% empty %}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-secondary mt-4"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
    There is no opinions yet for this book.
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {% endfor %}

<span class="hljs-comment">&lt;!--{% else %}--&gt;</span>
<span class="hljs-comment">&lt;!--&lt;div class="alert alert-secondary" role="alert"&gt;--&gt;</span>
<span class="hljs-comment">&lt;!--    Discussion is not enabled yet for this book.--&gt;</span>
<span class="hljs-comment">&lt;!--...--&gt;</span>
</code></pre>
<p>This is the beauty of Django - you access all the opinions users posted under a particular book with <code>book.discussion.all</code>.
Inside the <code>for tags</code>, you access its fields the same ways for the book - <code>opinion.field</code>.
Another thing you may noticed - <code>{% empty %}</code> tag.
This is a tag, used inside the <code>for loop</code> that executes if the list you loop through is empty.
If there's a discussion going on under the book, the details about every opinion will be displayed.
But if there's no discussion, the alert about no opinions will get displayed.</p>
<p>This means that instead of <code>{% if book.discussion.all %} ... {% else %}</code> you get to use <code>{% empty %}</code>.</p>
<h2 id="display-the-latest-book-for-discussion">Display the latest book for discussion</h2>
<p>Currently, discussing the book is not the first thing that comes to the user's mind when on your webpage.
Turn their attention to it by displaying the latest book they should read.</p>
<p>Add a 'featured' box at the top of your "bookclub/templates/bookclub/book_detail.html":</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--bookclub/templates/bookclub/book_detail.html--&gt;</span>
<span class="hljs-comment">&lt;!--...--&gt;</span>
<span class="hljs-comment">&lt;!--{% block content %}--&gt;</span>
{% if previous_books %}
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"jumbotron"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"lead"</span>&gt;</span>What were your thoughts on the latest book?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{previous_books.0.book}}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{previous_books.0.description|truncatewords:150}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary btn-lg"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{% url 'book_detail' pk=previous_books.0.pk %}"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span>&gt;</span>See the discussion<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{% endif %}
<span class="hljs-comment">&lt;!--&lt;ul class="nav ... --&gt;</span>
</code></pre>
<p>All you did here is select the first book from the array of the previous books and displayed its data.
To avoid an ugly error if there are no previous_books, you need to first check if there are any previous books.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616407646804/0hKqwge43.png" alt="finnished.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>The pool of knowledge of Django is deep and wide. You've only scratched a surface, but even with that, you can create a lot.
Now you know how to create a Django project and an app in it.
You learned a good flow for creating a page:
<code>Model</code> -&gt; <code>Url</code> -&gt; <code>View</code> -&gt; <code>Template</code>
You learned about template extending and how to make your pages prettier with Bootstrap.</p>
<blockquote>
<p>The whole code can be found on <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/complete-django-tutorial-part-1">GitLab</a>.</p>
</blockquote>
<p>This tutorial is the first in a series that covers Django from first steps to deployment. 
Feel free to stick around for the <a target="_blank" href="https://girlthatlovestocode.com/series/django">whole series</a>.
In the <a target="_blank" href>second part - COMING SOON</a>, you'll learn how to customize the admin interface, use Django packages, add custom CSS...</p>
]]></content:encoded></item><item><title><![CDATA[Your first Django REST API]]></title><description><![CDATA[Requirements

Basic knowledge of Python

Basic understanding of Django framework


REST API
Rest API is a term concatenated from 2 abbreviations.

REST stands for REpresentational State Transfer

API stands for Application Programming Interface


RES...]]></description><link>https://girlthatlovestocode.com/django-rest-api</link><guid isPermaLink="true">https://girlthatlovestocode.com/django-rest-api</guid><category><![CDATA[Django]]></category><category><![CDATA[REST API]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[REST]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 10 Mar 2021 11:32:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368550218/TpE69D7MS.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-requirements">Requirements</h2>
<ul>
<li><p>Basic knowledge of Python</p>
</li>
<li><p>Basic understanding of Django framework</p>
</li>
</ul>
<h2 id="heading-rest-api">REST API</h2>
<p>Rest API is a term concatenated from 2 abbreviations.</p>
<ul>
<li><p>REST stands for REpresentational State Transfer</p>
</li>
<li><p>API stands for Application Programming Interface</p>
</li>
</ul>
<p>REST is an architectural style for distributed hypermedia systems that abide by some rules.</p>
<ul>
<li><p>Client and server sides are separated.</p>
</li>
<li><p>Each request from the client to the server must contain all of the information (it is stateless).</p>
</li>
<li><p>Interface is uniformed (all the API points should be accessible by a similar approach).</p>
</li>
</ul>
<p>API is a specification by some software that allows other programs to interact with it. It allows a developer to make a specific request to send or receive information.</p>
<p><strong>So, REST API is a web service for programs that uses REST architectural style and abides by its rules.</strong></p>
<h2 id="heading-django-rest-framework">Django REST Framework</h2>
<p>Django REST Framework is a powerful tool for creating REST APIs based on Django. It comes with built-in serialization, authentication and it's highly customizable. Besides that, APIs built with it are browsable out of the box. That means that you're able to use it almost like a simple web application. You can add data and view it in a browser.</p>
<p>Another great thing is that it comes with <a target="_blank" href="https://www.django-rest-framework.org/">great documentation</a>.</p>
<h2 id="heading-squats-pushups-and-api">Squats, pushups, and API</h2>
<p>A bunch of programmer friends decided they want to do more for their bodies. They plan to do as many pushups and squats as they can each day and compete against each other. The person that does the most of both at the end of the period, gets a reward.</p>
<p>Since they're programmers, each of them will create their own client and analyze data in their own way. To be able to see where the competitors are, they need an API. They'll send their daily record to the API and will be able to retrieve data about others back.</p>
<p>Each day, they'll post how many pushups and squats they did, but they don't need daily records of others back. They just need to know the total count of both for every other competitor.</p>
<h2 id="heading-initial-setup">Initial setup</h2>
<p>Start with creating a project and virtual environment:</p>
<pre><code class="lang-sh">$ mkdir health_challenge
$ python3.9 -m venv env
$ <span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<p>Next, install Django and Django Rest Framework:</p>
<pre><code class="lang-sh">(env)$ pip install django
(env)$ pip install djangorestframework
</code></pre>
<p>After that, create a new Django project and app:</p>
<pre><code class="lang-sh">(env)$ django-admin.py startproject tutorial .
(env)$ django-admin.py startapp challenge
</code></pre>
<blockquote>
<p>adding a dot after the name of the project prevents Django from creating a redundant parent directory</p>
</blockquote>
<p>Once the project is created, register Django Rest Framework (DRF) and the challenge app to installed apps inside "tutorial/settings.py" :</p>
<pre><code class="lang-python"><span class="hljs-comment"># tutorial/settings.py</span>
INSTALLED_APPS = [
    <span class="hljs-comment"># ...</span>
    <span class="hljs-string">'django.contrib.messages'</span>,
    <span class="hljs-string">'django.contrib.staticfiles'</span>,
    <span class="hljs-string">'rest_framework'</span>,
    <span class="hljs-string">'challenge'</span>,
]
</code></pre>
<h2 id="heading-models">Models</h2>
<p>Create a Record model inside the "challenge/models.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/models.py</span>
<span class="hljs-keyword">from</span> django.utils <span class="hljs-keyword">import</span> timezone
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Record</span>(<span class="hljs-params">models.Model</span>):</span>
    date = models.DateField(default=timezone.now)
    pushups = models.PositiveIntegerField(default=<span class="hljs-number">0</span>)
    squats = models.PositiveIntegerField(default=<span class="hljs-number">0</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.date
</code></pre>
<p>For now, it has 3 attributes: date, pushups, and squats. You'll add the creator later.</p>
<p>Create an initial migration and apply it:</p>
<pre><code class="lang-shell">(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
</code></pre>
<p>Register the Record model in <code>challenge/admin.py</code> so you can access it from the Django admin panel:</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/admin.py</span>
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> challenge.models <span class="hljs-keyword">import</span> Record

admin.site.register(Record)
</code></pre>
<p>If you want to access the admin panel to check your work, you have to create a superuser:</p>
<pre><code class="lang-sh">(env)$ python manage.py createsuperuser
</code></pre>
<p>Enter the required data (remember the password!).</p>
<p>Now, run the local server for the very first time:</p>
<pre><code class="lang-sh">(env)$ python manage.py runserver
</code></pre>
<p>Navigate to the admin panel in your application: http://127.0.0.1:8000/admin/ and open Records. Add 2 new records.</p>
<h2 id="heading-serializers">Serializers</h2>
<p>Instead of a page composed of HTML, CSS, and JS, an API only provides <strong>raw data</strong>. That data needs to be in some kind of form that it's easy for a program to extract it (<code>JSON</code>/<code>XML</code>). In DRF, Serializer takes care of that. DRF Serializer covers serialization and deserialization of data and its validation. There are two possible classes to use when you need a serializer. <code>Serializer</code> class is a powerful generic way to control the output, <code>ModelSerializer</code> is a specialized serializer for model instances. Considering you're working with your models, you'll use the second one.</p>
<p>Create a new file <code>serializers.py</code> inside <em>challenge</em> directory:</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/serializers.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> serializers
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Record


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecordSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Record
        fields = (<span class="hljs-string">"id"</span>, <span class="hljs-string">"date"</span>, <span class="hljs-string">"pushups"</span>, <span class="hljs-string">"squats"</span>)
</code></pre>
<p><code>ModelSerializer</code>class creates a <code>Serializer</code> with a set of fields that corresponds to the selected <code>Model</code>. As you can see, you had to import the serializer and the <em>Record</em> model.</p>
<p>Inside the <code>ModelSerializer</code> there's a <code>class Meta</code> in which you specify which model you want to use and which fields from the Model to serialize.</p>
<blockquote>
<p>Even if you want to serialize all the data, it is recommended to specify each field explicitly. That saves you from exposing too much data by accident if you change your <code>Model</code>. Ignoring that, you can specify all the fields with <code>fields = "__all__"</code>.</p>
</blockquote>
<h2 id="heading-view">View</h2>
<p>Since you're not building a typical website, you won't use a classical Django <code>View</code>. DRF provides a <code>View</code> subclass - <code>APIView</code>.</p>
<p><code>GenericAPIView</code> which extends <code>APIView</code>, provides concrete generic views that cover commonly required behaviors for lists and detail views.</p>
<p>There are quite a few concrete generic views you could use:</p>
<ul>
<li><p><strong>CreateAPIView</strong> is used for resource creation endpoints</p>
</li>
<li><p><strong>ListCreateAPIView</strong> is used for a read-write list of resources</p>
</li>
<li><p><strong>RetrieveUpdateDestroyAPIView</strong> is used for read-write-delete on single resource</p>
</li>
<li><p>...</p>
</li>
</ul>
<blockquote>
<p>You can check all of them <a target="_blank" href="https://www.django-rest-framework.org/api-guide/generic-views/#concrete-view-classes">here</a></p>
</blockquote>
<p>Since you're creating an endpoint for posting the records, you'll use <strong>CreateAPIView</strong> generic view. Create a new file <em>view.py</em>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> RecordSerializer


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecordAdd</span>(<span class="hljs-params">generics.CreateAPIView</span>):</span>
    serializer_class = RecordSerializer
</code></pre>
<p>There is no data to retrieve, so you just need to set the <code>serializer_class</code> to the previously created <code>RecordSerializer</code>.</p>
<h2 id="heading-url">URL</h2>
<p>The last thing to do is to add an url where you can access your view. Create an <code>urls.py</code> inside the <em>challenge</em> folder.</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/urls.py</span>
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> .views <span class="hljs-keyword">import</span> RecordAdd

urlpatterns = [
    path(<span class="hljs-string">'add-record'</span>, RecordAdd.as_view())
]
</code></pre>
<p>After that, include that file inside "tutorial/urls.py":</p>
<pre><code class="lang-python"><span class="hljs-comment">#tutorial/urls.py</span>
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include

urlpatterns = [
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
    path(<span class="hljs-string">""</span>, include(<span class="hljs-string">"challenge.urls"</span>)),
]
</code></pre>
<p>Now you can navigate to http://127.0.0.1:8000/add-record and voila:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368590383/oO7j_0ozN.png" alt="record_add_view.png" /></p>
<p>Your first API endpoint!</p>
<p>Add a record and go check it in the admin panel: http://127.0.0.1:8000/admin/challenge/record/. You should see the record you entered via API!</p>
<h2 id="heading-record-owners">Record owners</h2>
<p>If your app is about the competition between record creators, you need to be able to assign created records to a user. That's how you'll know who made that many pushups.</p>
<p>Start by changing a <em>Record</em> model. You need to add a creator field to it.</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/models.py</span>
<span class="hljs-comment"># ...</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Record</span>(<span class="hljs-params">models.Model</span>):</span>
    date = models.DateField(default=timezone.now)
    pushups = models.PositiveIntegerField(default=<span class="hljs-number">0</span>)
    squats = models.PositiveIntegerField(default=<span class="hljs-number">0</span>)
    creator = models.ForeignKey(<span class="hljs-string">'auth.User'</span>, on_delete=models.CASCADE)

<span class="hljs-comment"># ...</span>
</code></pre>
<p>Stop the local server with <code>Ctrl+C</code> and run <code>(env)$ python manage.py makemigrations</code>. Since you've already created some records it won't go as easy as the first time.</p>
<p>You'll get asked the following:</p>
<pre><code class="lang-sh">You are trying to add a non-nullable field <span class="hljs-string">'creator'</span> to record without a default; you can<span class="hljs-string">'t do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py</span>
</code></pre>
<p>Select 1 and type 1 in again, so your superuser will be the creator of current records. Sync your database with <code>(env)$ python manage.py migrate</code>.</p>
<p>Make some minor changes, so you can check if your <code>Model</code> change works as it should.</p>
<p>First, create another superuser: <code>shell (env)$ python manage.py createsuperuser</code> Next, add a login to the browsable API. Include <code>rest_framework.urls</code> in the "tutorial/urls.py":</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include

urlpatterns = [
  path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
  path(<span class="hljs-string">'api-auth/'</span>, include(<span class="hljs-string">'rest_framework.urls'</span>)),
  path(<span class="hljs-string">""</span>, include(<span class="hljs-string">"challenge.urls"</span>)),
]
</code></pre>
<p>If you refresh the page (http://127.0.0.1:8000/add-record), you'll see a little arrow next to your username on the right side of the page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368621124/ti61WjKOA.png" alt="login.png" /></p>
<p>Click on it and you can logout and login with the other superuser you created.</p>
<p>After that, change the list display for records admin. Add a <em>RecordAdmin</em> with the <code>list_display</code> specified to the "challenge/admin.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/admin.py</span>
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> challenge.models <span class="hljs-keyword">import</span> Record

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecordAdmin</span>(<span class="hljs-params">admin.ModelAdmin</span>):</span>
    list_display = (<span class="hljs-string">'date'</span>, <span class="hljs-string">'creator'</span>)

admin.site.register(Record, RecordAdmin)
</code></pre>
<blockquote>
<p>This is not necessary, solely intent of this is that you can easily see who's the records creator.</p>
</blockquote>
<p>Now, logged in as another user, try to create a new record via browsable API and... Ups, you've got an error.</p>
<pre><code class="lang-plaintext">NOT NULL constraint failed: challenge_record.creator_id
</code></pre>
<p>That's because now you demand a creator in your model, but you didn't provide it. You don't want to add it via form, as you did it for other data. You want for the creator to be automatically added, based on which user posted the new record. You can hook on the objects save method in your view and overwrite it, so creator = user.</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/views.py</span>
<span class="hljs-comment"># imports here</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecordAdd</span>(<span class="hljs-params">generics.CreateAPIView</span>):</span>
    serializer_class = RecordSerializer

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">perform_create</span>(<span class="hljs-params">self, serializer</span>):</span>
        serializer.save(creator=self.request.user)
</code></pre>
<p>Try to create a record, logged in as another user again and you should see no error. Now, go check the records admin panel at http://127.0.0.1:8000/admin/challenge/record/ and you can see that you created another record with a different user.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368635830/-veN6Szyj.png" alt="list_records_admin.png" /></p>
<h2 id="heading-list-all-users-with-their-records">List all users with their records</h2>
<p>You covered the posting-the-record part. Now move to the second part of your requirements - getting the data for all the competitors. Before you proceed and make things complicated, start simple.</p>
<p>First, add a serializer <em>CompareSerializer</em> inside "challenge/serializers.py*:</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/serializers.py</span>
<span class="hljs-comment"># imports and RecordSerializer here</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CompareSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = User
        fields = (<span class="hljs-string">"__all__"</span>)
</code></pre>
<p>You retrieve all the data that you have on each user.</p>
<p>Next, add a new view inside "challenge/views.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/views.py</span>
<span class="hljs-comment"># imports and RecordAdd here</span>
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> RecordSerializer, CompareSerializer
<span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> User


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CompareView</span>(<span class="hljs-params">generics.ListAPIView</span>):</span>
    queryset = User.objects.all()
    serializer_class = CompareSerializer
</code></pre>
<p>There are some differences with the <code>RecordAdd</code> view:</p>
<ol>
<li><p>Instead of <code>CreateAPIView</code>, you use <code>ListAPIView</code> - that's because you don't want to add a new record but to see all the records.</p>
</li>
<li><p>You didn't need the queryset for <code>RecordAdd</code>, because you didn't do anything with previous records. Now you're showing all the records, so you need to retrieve them.</p>
</li>
<li><p>You used the <code>CompareSerializer</code> instead of <code>RecordSerializer</code></p>
</li>
</ol>
<p>After that, add an url to "challenge/urls.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/urls.py</span>
<span class="hljs-comment"># imports here</span>

urlpatterns = [
    path(<span class="hljs-string">'add-record'</span>, RecordAdd.as_view()),
    path(<span class="hljs-string">'compare'</span>, CompareView.as_view())
]
</code></pre>
<p>Now navigate to http://127.0.0.1:8000/compare and ... - ok, it's working but it's not the data you need.</p>
<h2 id="heading-serializermethodfields">SerializerMethodFields</h2>
<p><code>SerializerMethodField</code> is a read-only field that gets its value by calling a method on its Serializer. You can use it to add any sort of data to your serialized object.</p>
<p>Edit your <code>CompareSerializer</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/serializers.py</span>
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Sum
<span class="hljs-comment"># other imports and RecordSerializer</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CompareSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    pushups = serializers.SerializerMethodField()

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = User
        fields = (<span class="hljs-string">"username"</span>, <span class="hljs-string">"pushups"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_pushups</span>(<span class="hljs-params">self, obj</span>):</span>
        <span class="hljs-keyword">return</span> obj.records.aggregate(Sum(<span class="hljs-string">'pushups'</span>))[<span class="hljs-string">'pushups__sum'</span>]
</code></pre>
<p><code>SerializerMethodField</code> and its method are automatically connected with a DRF method <code>get_&lt;field_name&gt;</code>. That means that the belonging method has the same name as the field, just prefixed with <code>get_</code>. You need to add the <code>SerializerMethodField</code> to the <code>Serializer</code>s fields.</p>
<p>Now for the method: <code>obj</code> refers to the instance of <code>Model</code> you're using for your <code>Serializer</code>. <code>.aggregate</code> is a Django's function that summarizes a collection of objects and with <code>Sum</code>, you calculate their sum. <code>obj.records.aggregate(Sum('pushups'))</code>returns a dictionary, so you add <code>['pushups__sum']</code> to access just the desired key.</p>
<p>Refresh http://127.0.0.1:8000/compare and check if it works.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368651362/wVtt-0YL9.png" alt="pushups_sum.png" /></p>
<p>You got the count of pushups! To provide all the data you wanted, you just need to do the same for the squats.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CompareSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    pushups = serializers.SerializerMethodField()
    squats = serializers.SerializerMethodField()

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = User
        fields = (<span class="hljs-string">"username"</span>, <span class="hljs-string">"pushups"</span>, <span class="hljs-string">"squats"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_pushups</span>(<span class="hljs-params">self, obj</span>):</span>
        <span class="hljs-keyword">return</span> obj.records.aggregate(Sum(<span class="hljs-string">'pushups'</span>))[<span class="hljs-string">'pushups__sum'</span>]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_squats</span>(<span class="hljs-params">self, obj</span>):</span>
        <span class="hljs-keyword">return</span> obj.records.aggregate(Sum(<span class="hljs-string">'squats'</span>))[<span class="hljs-string">'squats__sum'</span>]
</code></pre>
<p>You added another <code>SerializerMethodFIeld</code> and its method. Don't forget to add this method field to the list of fields inside the <code>Meta</code> class. Refresh the page and the second <code>APIView</code> is completed!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368664447/SCPXmD6OP.png" alt="pushups_squats_count.png" /></p>
<h2 id="heading-limit-the-api-solely-to-authenticated-users">Limit the API solely to authenticated users</h2>
<p>You don't want the data of your users to be seen by anyone who just wanders around your API. You want to limit the access to this API point. There are 3 options for limiting the access:</p>
<ul>
<li><p>Project-level (restrict the access to the whole API)</p>
</li>
<li><p>View-level (restrict the access to whole API View)</p>
</li>
<li><p>Object-level (restrict the access only for part of the view)</p>
</li>
</ul>
<h3 id="heading-default-permission-policy">Default permission policy</h3>
<p>Currently, you don't want someone that is not registered, to see anything. You'll restrict access to your API globally. Edit "tutorial/setting.py" and add this at the bottom:</p>
<pre><code class="lang-python">REST_FRAMEWORK = {
    <span class="hljs-string">'DEFAULT_PERMISSION_CLASSES'</span>: [
        <span class="hljs-string">'rest_framework.permissions.IsAuthenticated'</span>,
    ]
}
</code></pre>
<p>With this, you allow access to your API only to authenticated users. Logout from the API and you'll see this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368682259/X-_b4OwtL.png" alt="access_restricted.png" /></p>
<p>Even if you navigate to <em>/add-record</em>, the message you will be the same.</p>
<p>Remember how to do that, but for now, delete the code you added in the <code>settings.py</code> file (<code>REST_FRAMEWORK ... IsAuthenticated',]}</code>). You need to learn about another possibility.</p>
<h3 id="heading-view-level-permission">View level permission</h3>
<p>Let's say the family and friends of the competitors want to monitor the competition. You want them to see the list of competitors, but you don't want them to add the records. If they'd try, they'd get a nasty error:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368696230/qqNuSPzbz.png" alt="not_authenticated_error.png" /></p>
<p>You don't want that. You want to limit the access for the <code>add-record</code> endpoint.</p>
<p>Edit the <code>RecordAdd</code> class in "challenge/views.py":</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/views.py</span>

<span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> IsAuthenticated <span class="hljs-comment"># don't forget the import!</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecordAdd</span>(<span class="hljs-params">generics.CreateAPIView</span>):</span>
    permission_classes = [IsAuthenticated]

    serializer_class = RecordSerializer

    <span class="hljs-comment"># ...</span>
</code></pre>
<p>Open http://127.0.0.1:8000/add-record. You're logged out, so this is the view you get to see:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368716644/54unt1pDi.png" alt="add_restricted.png" /></p>
<p>Now navigate to http://127.0.0.1:8000/compare. Even when you're logged out, your view is the same as for an authenticated user:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368730103/FoCfMTjO8.png" alt="compare_open.png" /></p>
<p>If you log in and go back to <em>/add-record</em>, you'll be able to post a new record:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368744756/1rq31VTXN.png" alt="logged_in.png" /></p>
<blockquote>
<p>Check all the possibilities of the restrictions <a target="_blank" href="https://www.django-rest-framework.org/api-guide/permissions/#api-reference">here</a>.</p>
</blockquote>
<h2 id="heading-root-api-endpoint">Root API Endpoint</h2>
<p>You can make your API easier to browse. On your root page(<code>/</code>), you want to make a list of all the endpoints.</p>
<p>For that, you need to create another view and connect it with the root url.</p>
<p>For this, you don't need Serializer, you'll use just a simple Django function-based view.</p>
<p>Add this at the top of the "challenge/views.py"e:</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/views.py</span>
<span class="hljs-comment"># ... imports here</span>
<span class="hljs-meta">@api_view()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">api_root</span>(<span class="hljs-params">request, format=None</span>):</span>
    <span class="hljs-keyword">return</span> Response({
        <span class="hljs-string">'add'</span>: reverse(<span class="hljs-string">'add-record'</span>, request=request, format=format),
        <span class="hljs-string">'compare'</span>: reverse(<span class="hljs-string">'compare'</span>, request=request, format=format)
    })

<span class="hljs-comment"># ... RecordAdd and CompareView here</span>
</code></pre>
<p>Django receives an instance of <code>HttpRequest</code> and returns <code>HttpResponse</code>, but DRF receives an instance of <code>Request</code> and returns <code>Response</code>. To change a Django view to a DRF view, use the <code>@api_view</code> decorator. You provide both API points in the <code>Response</code>. <code>reverse</code> returns a fully qualified URL, using the request to determine the host and port. That way, the urls are correct, either on your localhost or in the production, without the need to change anything in the code.</p>
<p><code>add-record</code> inside the <code>reverse</code> method corresponds to the name of the url. You don't have that in your "challenge/urls.py". Add it:</p>
<pre><code class="lang-python"><span class="hljs-comment"># challenge/urls.py</span>

<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path

<span class="hljs-keyword">from</span> .views <span class="hljs-keyword">import</span> RecordAdd, CreatorList, CompareView, api_root

urlpatterns = [
    path(<span class="hljs-string">'add-record'</span>, RecordAdd.as_view(), name=<span class="hljs-string">'add-record'</span>),
    path(<span class="hljs-string">'compare'</span>, CompareView.as_view(), name=<span class="hljs-string">'compare'</span>),
    path(<span class="hljs-string">''</span>, api_root)
]
</code></pre>
<p>You imported the <code>api_root</code> view you wrote a few minutes back and added it to the root of your website. To the paths <code>add-record</code> and <code>compare</code> you added names, so the <code>reverse</code> function in <code>api_root</code> can find them.</p>
<p>Open http://127.0.0.1:8000/ and check it yourself - it works!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615368759432/b88nX5aQg.png" alt="api_root.png" /></p>
<p>You can also click on links of <code>add</code> and <code>compare</code> and that makes it easy to navigate through your API.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You're now able to create a REST API with Django Rest Framework. You know how to create views that either allow you to post or to retrieve data. You know how to create serializers that change your <code>Model</code> data to <code>JSON</code>. You learned how to restrict access and how to make your API browsable. You also learned how to change the data you get from the <code>Models</code> and serve the change data on your API.</p>
<p>You can play around with it a little more:</p>
<ul>
<li>create an endpoint that will output the current winner</li>
</ul>
<p>create an endpoint where only an owner will be able to see and change/delete their record</p>
<p>If you're looking for more advanced content, you can check the articles on DRF that I wrote on Testdriven.io:<br />- <a target="_blank" href="https://testdriven.io/blog/drf-views-part-1/"><strong>Django REST Framework Views series</strong></a><br /><strong>-</strong> <a target="_blank" href="https://testdriven.io/blog/drf-permissions/"><strong>Permissions in Django REST Framework series</strong></a></p>
<p><sub>Image by slightly_different on Pixabay</sub></p>
]]></content:encoded></item><item><title><![CDATA[#ChooseToChallenge: Don't just bring me flowers]]></title><description><![CDATA[When I was a teenager, March 8 was just a day that women got flowers.
But in the last few years, International Women's day became more and more important to me.
As blog posts of my fellow coder's show, we're nowhere near the goal of men and women bei...]]></description><link>https://girlthatlovestocode.com/dont-just-bring-me-flowers</link><guid isPermaLink="true">https://girlthatlovestocode.com/dont-just-bring-me-flowers</guid><category><![CDATA[#ChooseToChallenge]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 03 Mar 2021 12:01:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614772455555/mfw2AEfsL.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I was a teenager, March 8 was just a day that women got flowers.
But in the last few years, International Women's day became more and more important to me.
As <a target="_blank" href="https://hashnode.com/n/choosetochallenge">blog posts</a> of my fellow coder's show, we're nowhere near the goal of men and women being equal.
And flowers are not going to change that.
But things like #choosetochallenge might.</p>
<h2 id="place-for-our-voice">Place for our voice</h2>
<p>Although the end goal is to make men and women equally present in the tech field, we're not there yet.
And striving toward that goal means that we need to take some measures until those measures will eventually become obsolete.
That means special treatment of women.</p>
<p>It's hard for the only woman in the team to speak up.</p>
<p>It's hard for a female developer on Twitter to be loud when she sees 20 'Twitter-famous' female developers and 200 male ones.</p>
<p>It's hard for a woman to go to a conference where she'll be surrounded by male developers.</p>
<p>That's why special places need to exist.</p>
<p>Places, where she doesn't need to be brave to speak.</p>
<p>Places, where she's especially welcomed.</p>
<p>That's why I'm glad #choosetochallenge exists.</p>
<p>That's why I love it when there are some tickets at the event reserved especially for women.</p>
<p>And that's why I occasionally create a tweet where people are invited to tag only women coders, not everyone.</p>
<p>And that's why I have an invitation for female coders to write to me in my Twitter bio.</p>
<p><strong>Because we need that special place, for now.</strong></p>
<h2 id="inappropriate-behavior">Inappropriate behavior</h2>
<p>There are very obvious inappropriate behaviors that put women in an inferior position.
Like a male coworker's uninvited sexual attention towards you.
Or your coworkers commenting on a physical appearance of a client or a coworker.
The workplace is not a place where this kind of behavior should be tolerated.</p>
<p>But there are less obvious acts that are hurtful toward women:</p>
<ul>
<li><p><strong>Saying that a woman in tech/any other male-dominated career is unfeminine</strong></p>
<p>No behavior makes a woman more or less feminine. She is who she is.</p>
</li>
</ul>
<ul>
<li><p><strong>Being surprised she can do something despite her being a woman</strong></p>
<p>Admiring some skill some woman has is great. But singing her praises just because she did something that is not expected for her gender (like hammering a nail in) is sexist.</p>
</li>
</ul>
<ul>
<li><p><strong>Expecting her to do something just because she's a woman is sexist.</strong></p>
<p>Always putting the task of writing notes during a meeting to a woman, because she probably 'has a pretty handwriting' is sexist and not appropriate for the 21st century.</p>
</li>
</ul>
<ul>
<li><p><strong>Sexist jokes</strong></p>
<p>Just because you camouflage it as a joke, it doesn't mean it's ok.</p>
</li>
</ul>
<h2 id="future-generations">Future generations</h2>
<p>Changes this big take time. And even though many of us are taking the steps toward reshaping the perception of women in tech, a non-gender biased environment in tech is probably something that only future generations will be able to experience.</p>
<p>Teach your daughters, nieces, and other little girls that they can do whatever they put their minds to, not just 'girl' things.
Try to spark their interest in science, math, and programming.
Don't teach your kids about 'male' and 'female' roles.
Teach your sons and nephews to respect women and that household chores are something that should be done by "people", not by women.</p>
<p>Don't limit a little woman to your expectations.
Her wanting to wear a blue shirt and playing with dinosaurs is great.
Her wearing a pink skirt and playing with barbies is great.</p>
<p>I once saw a little girl in a skirt playing soccer. She was the best little goalkeeper I ever saw.
It was awesome.
She took something considered 'feminine' and something considered 'masculine' and made it her own.</p>
<h2 id="motherhood">Motherhood</h2>
<p>Becoming a parent changes a lot and this is more true for the mothers.
Pregnancy many times requires either to work less or take the time off and in the countries that have maternity leave, that means leaving the workforce for a while.
When coming back, you have a tiny human being to take care of and that makes a good work-life balance a necessity.
According to the research by <a target="_blank" href="https://www.gendereconomy.org/the-damaging-effect-of-gendered-views-of-work-life-balance/">Christine L. Williams</a>,
mothers and prospective mothers experience intense work-life conflict.</p>
<p>We need to stop equating a good employee with an employee that works long hours.
That puts mothers at an unfair disadvantage. Even if she's highly efficient, she isn't perceived like that, because she doesn't work long hours and she takes time off to take care of a sick child.
We also need to stop allowing for maternity leave to affect the career.
Temporarily leaving a job to take care of a little human being that on your old age might be your doctor or your kind neighbor is important, not just for her and her child, but also for you.
And it should be respected, not looked down on.</p>
<p>The expectation of a woman having a kid and start working less also concerns the child-less.
Employees will expect her to have a child eventually and will be reluctant to give her a job in the first-place or promotion later in the career.</p>
<p><strong>Pandemic hit mothers hard.</strong></p>
<p>According to <a target="_blank" href="https://www.nytimes.com/2020/10/29/upshot/mothers-leaving-jobs-pandemic.html">The New York Times</a>, 900.000 mothers left the workforce due to pandemic in the USA.</p>
<p>I, living in Europe, had to revise my career plans because kindergartens were closed for months and can close again in a matter of days.
Once the pandemic is over, we need to do everything in our power to help those women to get back in the workforce.
And we must not see them leaving as a weakness and something that puts them at a disadvantage.
They already made their sacrifice, let's not make them sacrifice even more.</p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>The coding world is a world of great opportunities.
But in a world where women are so scarce, it can be hard being a woman.</p>
<p>If you're a woman, be brave, so the next generations won't need to be.</p>
<p>If you're a man, don't be mad if we get special treatment. We need it, so we won't need it anymore.</p>
<p><strong>Happy International Women's day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Dipping my toes in Test-Driven Development with Python]]></title><description><![CDATA[Intro
When you start learning you create an application, maybe even deploy it on some free server, but that's it. There is no unsatisfied customer that found some error, there is no client that changed their requirements 3 hours after you pushed to p...]]></description><link>https://girlthatlovestocode.com/test-driven-development</link><guid isPermaLink="true">https://girlthatlovestocode.com/test-driven-development</guid><category><![CDATA[TDD (Test-driven development)]]></category><category><![CDATA[unit testing]]></category><category><![CDATA[test]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Mon, 01 Mar 2021 09:29:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614590874481/BEKO8XyK2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-intro">Intro</h2>
<p>When you start learning you create an application, maybe even deploy it on some free server, but that's it. There is no unsatisfied customer that found some error, there is no client that changed their requirements 3 hours after you pushed to production. There is also no code maintenance. In reality, software is a living thing.</p>
<p>In a real-life, you'll keep changing your code, adding new requirements, fixing bugs. And that can get messy after a while.</p>
<p>There are some practices that make it easier for you. One of those is Test Driven Development.</p>
<h2 id="heading-requirements">Requirements</h2>
<p>Since this is not a tutorial, you don't really need any knowledge to read it. However, I assume that you know enough Python to be able to follow.</p>
<h2 id="heading-what-is-test-driven-development">What is Test Driven Development</h2>
<p>Test-Driven Development with the abbreviation TDD is a methodology in software development where you write a test for function <strong>before</strong> it is implemented.</p>
<p>Writing TDD means writing in a cycle:</p>
<ol>
<li><p>RED - write failing test</p>
</li>
<li><p>GREEN - write the simplest piece of code that will get the test to pass</p>
</li>
<li><p>REFACTOR - improve the code while keeping the test pass</p>
</li>
</ol>
<p>Although it seems that it takes a longer time to develop that way, it saves you a lot of time after you've mastered it. Similarly, it costs you a lot of nerves when you start learning it but it saves you a lot of nerves in a long run.</p>
<h3 id="heading-palindrome-example">Palindrome example</h3>
<p>I wrote a simple function, that checks if a string is a palindrome. The only palindrome I know on the top of my head is the word "tat" (it means a thief in my language).</p>
<p>A word is very simple to check: you just have to revert it. If words are the same, you know that is a palindrome. You don't naturally think about 10 other cases in which that maybe wouldn't work. It works and that's enough.</p>
<p>But, because I was practicing TDD, I had more cases that got run. It turned out that my function didn't work for sentences. Sentences included capital letters, spaces, and punctuations. Because of TDD, I quickly figured out I need to remove special characters and spaces.</p>
<p>That mistake is easy to catch, but when your code is more complex, it can take a lot of time to figure out that something is not okay and how to fix that.</p>
<h2 id="heading-what-i-was-doing">What I was doing</h2>
<p>For my first project, I selected something simple. If I would be developing something complex, my focus would be on the development of the program instead of on learning TDD.</p>
<p>I was building an expense tracker where the user can enter an amount, date, and description of expense via CLI which is stored in the database. It's also possible for the user to list existing expenses.</p>
<p>To build it I used:</p>
<ul>
<li><p>Python</p>
</li>
<li><p>pytest</p>
</li>
<li><p>TXT file as a database</p>
</li>
</ul>
<h2 id="heading-given-when-and-then">Given, when and then</h2>
<p><code>Given, when, then</code> is a structure that you can use to describe the expected behavior of the unit under test. In Python you can write it as a docstring:</p>
<pre><code class="lang-plaintext">"""
GIVEN:  initial conditions for the test
WHEN:   what is occurring that needs to be tested?
THEN:   expected outcome
"""
</code></pre>
<p>I always wrote that docstring first and use it as a guideline to write the test. It's also easier to see what's going on for someone who sees the test for the first time.</p>
<h2 id="heading-my-first-test">My first test</h2>
<p>First, I installed pytest. It's a Python library for writing automated tests. I started with a unit test. The unit test is a test that tests a small part of the program in isolation of other parts. To check whether those units work together correctly you use integration and end-to-end tests. When I started writing the test for my first function there was no code yet. At this point, function <em>user_input_divide</em>, existed only in my head. So I wrote a test for it:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_user_input_divide</span>():</span> <span class="hljs-comment">#1</span>
    <span class="hljs-comment">#2</span>
    <span class="hljs-string">"""
    GIVEN user input
    WHEN user_input_divide is called
    THEN input is divided into 3 pieces (amount, date, description)
    """</span>

    raw_input = <span class="hljs-string">"33.22;2020-11-05;This is a description"</span> <span class="hljs-comment">#3</span>
    amount, date, description = user_input_divide(raw_input) <span class="hljs-comment">#4</span>

    <span class="hljs-comment">#5</span>
    <span class="hljs-keyword">assert</span> amount == <span class="hljs-string">"33.22"</span>
    <span class="hljs-keyword">assert</span> date == <span class="hljs-string">"2020-11-05"</span>
    <span class="hljs-keyword">assert</span> description == <span class="hljs-string">"This is a description"</span>
</code></pre>
<ol>
<li><p>name of the test function must be prepended with <em>test_</em> - pytest automatically discover and runs functions with <em>test_</em> prefix</p>
</li>
<li><p>Given, when, then formula:</p>
<ul>
<li><p>Given a user input -in this function I do not care how will I get user input, I just assume it exists and it's in the correct form.</p>
</li>
<li><p>the function <em>user_input_divide</em> is going to be called user_input_divide</p>
</li>
<li><p>as a result user's input must be divided into 3 pieces - amount, date, description</p>
</li>
</ul>
</li>
<li><p>valid user's input for the function</p>
</li>
<li><p>function <code>user_input_divide</code> is called to divide the input - the function <code>user_input_divide</code> doesn't exist yet.</p>
</li>
<li><p><code>assert</code> is a standard Python statement that can be used with pytest. On the left side, you provide the actual outcome of the function and on the right side, you provide the expected outcome. <code>==</code> in the middle means that you expect that both sides will be equal</p>
</li>
</ol>
<p>After that, I ran the test with the command:</p>
<pre><code class="lang-sh">pytest
</code></pre>
<p>The test, of course, fails.</p>
<p>Once I had a failing test I implemented a function with a hardcoded result.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_input_divide</span>(<span class="hljs-params">raw_input</span>):</span>
    <span class="hljs-keyword">return</span> [<span class="hljs-string">"33.22"</span>, <span class="hljs-string">"2020-11-05"</span>, <span class="hljs-string">"This is a description"</span>]
</code></pre>
<p>I run the test again and it failed - again.</p>
<p>Why? Let's read the error:</p>
<pre><code class="lang-python">NameError: name <span class="hljs-string">'user_input_divide'</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> defined
</code></pre>
<p>Of course, I haven't imported the function into my test module yet.</p>
<p>That should fix it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> expense.user_input <span class="hljs-keyword">import</span> three_part_input, user_input_divide

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_user_input_divide</span>():</span> <span class="hljs-comment">#1</span>
    ...
</code></pre>
<p>I run the test again, it passed.</p>
<p>But that didn't cut it. That function didn't do anything, I just knew that everything is connected the right way.</p>
<p>I changed the function from hardcoded to real implementation:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_input_divide</span>(<span class="hljs-params">raw_input</span>):</span>
    <span class="hljs-keyword">return</span> raw_input.split(<span class="hljs-string">";"</span>)
</code></pre>
<p>I run the test and it passed.</p>
<blockquote>
<p>This article didn't go into detail regarding <code>pytest</code>.<br />If you want to learn more. check out my <a target="_blank" href="https://testdriven.io/blog/pytest-for-beginners/">Pytest for beginners article</a>.</p>
</blockquote>
<h2 id="heading-where-to-next">Where to next?</h2>
<p>Imagine TDD like building something with Legos. First, you create all the lego blocks, and only after that, you put them together. Following the expense tracker example, it would go something like this:</p>
<ul>
<li><p>Splitting user input into 3 separated parts - DONE</p>
</li>
<li><p>Checking if all the data is in a correct form (date in form of YYYY-mm-dd, the amount in a form of a float)</p>
</li>
<li><p>Currently, all the data is in a string - you need to transform the amount into a float and date into a datetime object</p>
</li>
<li><p>Put date into the object</p>
</li>
<li><p>Persist the object to a database</p>
</li>
</ul>
<p>For each of these, you first need to write a test. Only after that, you put all that together and test if it works correctly altogether.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This was not meant to teach you test-driven development but to introduce it to you. I hope I sparked a little interest in TDD. It's a great way towards easier development, maintenance, and upgrading. I recently started learning TDD, so you can follow my journey here. I'm also planning to create beginner-friendly tutorials in the future.</p>
<p>Photo by Samuele Errico Piccarini on Unsplash</p>
]]></content:encoded></item><item><title><![CDATA[Delightful accordion]]></title><description><![CDATA[Accordions are useful when you want to present key information right away and give interested users the ability to learn more about the topic with a single click.
In this tutorial, you'll create a stylish accordion. Along the way, you'll learn how to...]]></description><link>https://girlthatlovestocode.com/accordion</link><guid isPermaLink="true">https://girlthatlovestocode.com/accordion</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Fri, 19 Feb 2021 09:51:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613728753479/xo0KlKAPd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Accordions are useful when you want to present key information right away and give interested users the ability to learn more about the topic with a single click.</p>
<p>In this tutorial, you'll create a stylish accordion. Along the way, you'll learn how to combine <code>::before</code> and <code>::after</code> to create a beautiful effect, how to toggle class and content, and many more.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>basic knowledge of HTML</li>
<li>basic knowledge of CSS</li>
<li>basic knowledge of JS</li>
</ul>
<h2 id="pretty-bullet">Pretty bullet</h2>
<p>Let's start building with pretty bullet. First, create a new file <em>accordion.html</em>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Beautifull accordion<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"accordion.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.5.1.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"accordion.js"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"accordion"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"outer"</span>&gt;</span>
            Coding and programming careers have great earning potential
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inner"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hide"</span>&gt;</span>
            One of the strongest and most obvious draws of learning to code is the earning potential for coding and programming professionals. The Bureau of Labor Statistics (BLS) tracks salary and other important workforce information for a variety of careers.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Accordion will be built inside <code>&lt;div&gt;</code> with class <code>accordion</code>. It contains another <code>&lt;div&gt;</code> with class <code>tab</code> that contains:</p>
<ul>
<li><code>&lt;h3 class="outer"&gt;</code>- it contains key information and <code>&lt;span&gt;</code> that we'll be used create pretty bullet.</li>
<li><code>&lt;p class="innder"&gt;</code> - it contains more detailed information shown under the key information after click</li>
</ul>
<blockquote>
<p>At the moment there's a single accordion element. You'll add more of them later on.</p>
</blockquote>
<p>After that, create a new file <em>accordion.css</em>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.outer</span> {
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#082c42</span>;
}

<span class="hljs-selector-class">.inner</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.inner</span><span class="hljs-selector-pseudo">::before</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"images/button.svg"</span>);
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">position</span>: absolute;
}

<span class="hljs-selector-class">.inner</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">"•"</span>;
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#082c42</span>;
}
</code></pre>
<p>Here you have 4 elements on 3 levels:</p>
<ul>
<li><code>.outer</code> is a container whose only purpose is to hold some text and <code>.inner</code> span.</li>
<li><code>.inner</code> that holds <code>::before</code>/<code>::after</code></li>
<li><code>::before</code> and <code>::after</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727706465/QvJn24eHu.png" alt="single_bullet.png" /></p>
<p><code>.outer</code> is a container for your single bullet. The position of all the absolute positioned elements is based on a non-statically positioned ancestor. By setting the position to relative, you don't move the container, but you make it non-static, so all our absolute positioned elements will be positioned regarding the <code>.outer</code>. You set the line-height on <code>.outer</code> so all descendants will have the same line-height - that makes it easier to align them. With padding on the left, you get a little breathing room where you will now have space to put your pretty bullet.</p>
<p><code>.inner</code>'s purpose is to contain <code>::before</code> and <code>::after</code>. It doesn't hold anything but that. Both, <code>::before</code> and <code>::after</code> will be positioned furthest to the left, thus we position their parent as absolute with <code>left: 0</code>.</p>
<p>With the <code>::before</code>'s help, we show that pretty 3D button.</p>
<p>Next, create a new directory "images". After that, download the image for the bullet <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/pretty-accordion/-/tree/master/images">here</a> and store it inside "images".</p>
<p>Because it's an SVG you're able to set width and height. That works because the element is positioned absolutely. By default, <code>&lt;span&gt;</code> is an inline element and you can't define its width or height. But any element that is positioned absolutely, automatically acts as a block element.</p>
<p><code>::after</code> is containing a bullet(•). By making the element the same width and height you make it easier to put it in the middle of the larger circle just with <code>text-align: center</code></p>
<blockquote>
<p>Read about <code>::before</code> and <code>::after</code> <a target="_blank" href="https://girlthatlovestocode.com/css-pseudo-elements-before-and-after">here</a></p>
</blockquote>
<h2 id="add-javascript">Add JavaScript</h2>
<p>Once you hace HTML and CSS ready you need to add JavaScript. Add a new file <em>accordion.js</em>.</p>
<pre><code class="lang-js">$(<span class="hljs-built_in">document</span>).ready(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    $( <span class="hljs-string">".outer"</span> ).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        $(<span class="hljs-built_in">this</span>).closest(<span class="hljs-string">".tab"</span>).toggleClass(<span class="hljs-string">"active"</span>);
    })
})
</code></pre>
<p>The color of the middle circle on the bullet should change when clicked on. You can accomplish that by adding another class on the parent tab of the clicked <code>&lt;h3 class="outer"&gt;</code>. So when the user click on the <code>&lt;h3 class="outer"&gt;</code>, parent tab is found by <code>$(this).closest(".tab")</code>. <code>toggleClass</code> is a wonderful jQuery function, that adds or removes a class.</p>
<p>You need to include jQuery and <em>accordion.js</em> inside <em>accordion.html</em>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Beautifull accordion<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"accordion.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.5.1.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"accordion.js"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"accordion"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"outer"</span>&gt;</span>
            Coding and programming careers have great earning potential
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inner"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hide"</span>&gt;</span>
            One of the strongest and most obvious draws of learning to code is the earning potential for coding and programming professionals. The Bureau of Labor Statistics (BLS) tracks salary and other important workforce information for a variety of careers.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Open <em>accordion.html</em> in your browser with Developer's tools opened. Try <code>toggleClass</code> functionality by clicking on <code>&lt;h3 class="outer"&gt;</code>. You'll see that class gets added or removed on the <code>.tab</code> when you click. Visualy, there are no changes yet. To do that you have to target the smaller circle with <code>.inner::after</code> when <code>.tab.active</code> in your css and set it to different color:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.tab</span><span class="hljs-selector-class">.active</span> <span class="hljs-selector-class">.inner</span><span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#bfd7ed</span>;
}
</code></pre>
<p>Now, if you click on it repeatedly, it alternates colors based on class <code>active</code>.</p>
<h2 id="hide-detailed-content">Hide detailed content</h2>
<p>Detailed content should not show at first. It should slowly slide down when you click on <code>&lt;h3 class="outer"&gt;</code> (when the tab is <code>active</code>) and slide back up when you click on it again.</p>
<p>To do that you need to add a new class to <em>accordion.css</em>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.hide</span> {
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>To add slide effect you need to use <code>slideToggle</code> function. Edit your <em>accordion.js</em> to look like this:</p>
<pre><code class="lang-js">$(<span class="hljs-built_in">document</span>).ready(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    $( <span class="hljs-string">".outer"</span> ).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        $(<span class="hljs-built_in">this</span>).closest(<span class="hljs-string">".tab"</span>).toggleClass(<span class="hljs-string">"active"</span>);
        $(<span class="hljs-built_in">this</span>).siblings(<span class="hljs-string">".hide"</span>).slideToggle(<span class="hljs-string">"slow"</span>);
    })
})
</code></pre>
<p>The added line is pretty similar to the previous one. It finds a sibling of the clicked element that has a class <code>hide</code> and toggles the slide. Now, when you click on the <code>.outer</code>, the bullet changes color, and the content either opens or closes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727727797/3aI94CyPK.png" alt="single.png" /></p>
<h2 id="accordion">Accordion</h2>
<p>You can't really call it an accordion if it contains only one tab. so let's fix this. Edit your <em>accordion.html</em> to look like this:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Beautifull accordion<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"accordion.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.5.1.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"accordion.js"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"accordion"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"outer"</span>&gt;</span>
            Coding and programming careers have great earning potential
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inner"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hide"</span>&gt;</span>
            One of the strongest and most obvious draws of learning to code is the earning potential for coding and programming professionals. The Bureau of Labor Statistics (BLS) tracks salary and other important workforce information for a variety of careers.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"outer"</span>&gt;</span>
            Demand remains strong for coding-related jobs
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inner"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hide"</span>&gt;</span>
            When compared to the national average of five percent growth, you can see that a handful of positions are outpacing a lot of other careers. Computer programmers are an interesting outlier from this group, but some believe these projections are influenced by computer programming skills blending into other related in-demand tech roles.         <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"outer"</span>&gt;</span>
            Coding ability gives new perspective to problem-solving
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inner"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hide"</span>&gt;</span>
            Coding, in its most basic terms, is just assigning a computer a task to do based on the logical guidelines you’ve outlined. Highly complex tasks are essentially a collection of smaller operations once you break them down. This methodical and logic-heavy approach to problem-solving can be a boon for figuring out problems beyond a coding challenge.         <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Your HTML stayed the same, except that you added two more tabs inside the accordion. Check your browser, you'll see that it still works as intended.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727752660/Kt8O2dVHN.png" alt="multiple.png" /></p>
<p>There's only one problem - it doesn't look like an accordion. It looks like a bunch of text that can be shown or hidden. To improve that, let's create a line on the left side that will connect all tabs.</p>
<h2 id="line-on-the-left">Line on the left</h2>
<p>The line should run at the middle of your bullets and be covered by them where necessary. If you want the freedom to move it as you like, you can't create it as a border but as its own element. You'll use <code>::before</code> for creating it. Add these classes to <em>accordion.css</em>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.accordion</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.accordion</span> <span class="hljs-selector-class">.tab</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">border-left</span>: solid <span class="hljs-number">#979797</span> <span class="hljs-number">1px</span>;
    <span class="hljs-attribute">content</span>: <span class="hljs-string">''</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">bottom</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">z-index</span>: -<span class="hljs-number">1</span>;
}
</code></pre>
<p>Although it looks like one line, it's created by multiple lines - from one tab to another. You want to take them(it) out of the page flow, so they're positioned absolutely. As mentioned before, you need to position an ancestor as <code>relative</code> for this to work - <code>.accordion {position: relative;}</code>. If you skip that step, you'll see that the line stretches through the whole browser.</p>
<p>The <code>::before</code> doesn't have any content, just left border. <code>left: 20px;</code> positions it in the middle of the circle.
<code>z-index: -1;</code> puts it behind the bullet and <code>top: 0; bottom: 0;</code> stretches it from beginning to the end of the tab.</p>
<p>It looks pretty when it's closed, right? Not so much when it's opened.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727769842/UAqyNY58K.png" alt="line_over_text.png" /></p>
<p>Let's fix that.</p>
<h2 id="small-css-repairs">Small CSS repairs</h2>
<p>You want to move the detaild text to the right, so it aligns with the key point text. To do that, add padding to <code>.hide</code> class inside <em>accordion.css</em>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.hide</span> {
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">50px</span>; <span class="hljs-comment">/* newly added */</span>
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>You also want to make the accordion narrower. To do that, limit max width of <code>.accordion</code> to <em>800px</em> inside <em>accordion.css</em>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.accordion</span> {
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727789931/WxwIwj32Y.png" alt="css_fixes.png" /></p>
<p>This looks much better, doesn't it?</p>
<h2 id="only-one-tab-opened">Only one tab opened</h2>
<p>For now, if you click on a tab, it opens and if you click on it again, it closes. Clicking on another tab has no impact on all the other tabs. But there should be only one tab open at a time. When you click on one tab it should open and all the others should close.</p>
<p>Once again, edit <em>accordion.js</em>:</p>
<pre><code class="lang-js">$(<span class="hljs-built_in">document</span>).ready(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    $( <span class="hljs-string">".outer"</span> ).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        $(<span class="hljs-built_in">this</span>).closest(<span class="hljs-string">".tab"</span>).toggleClass(<span class="hljs-string">"active"</span>);
        $(<span class="hljs-built_in">this</span>).siblings(<span class="hljs-string">".hide"</span>).slideToggle(<span class="hljs-string">"slow"</span>);
        $(<span class="hljs-built_in">this</span>).closest(<span class="hljs-string">".tab"</span>).siblings(<span class="hljs-string">".tab.active"</span>).find(<span class="hljs-string">".hide"</span>).slideUp(<span class="hljs-string">"slow"</span>) <span class="hljs-comment">// added</span>
        $(<span class="hljs-built_in">this</span>).closest(<span class="hljs-string">".tab"</span>).siblings(<span class="hljs-string">".tab.active"</span>).removeClass(<span class="hljs-string">"active"</span>) <span class="hljs-comment">// added</span>
    })
})
</code></pre>
<p>From the <code>&lt;h3&gt;</code> on which you clicked, it moves to its tab parent. Then it finds tab's siblings that have class <code>active</code>. If you did that correctly, there shouldn't be more than one active tab. After that, it slides up the child with class <code>hide</code>, and then it removes the <code>active</code> class from the found tab.</p>
<p>If you play around a little in your browser, you can see that now there is always max one tab open, but you can also close the open one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727806980/j0ZgA0VOW.png" alt="one_open.png" /></p>
<p>If you paid attention, you'll notice that you're not finished yet. There's a little skip when the text is sliding up and it doesn't look good.</p>
<p>That's because you have an unwanted margin for <code>&lt;h3&gt;</code>. It is added by the browser.</p>
<h2 id="last-css-fixes">Last CSS fixes</h2>
<p>Because there's only one thing on your page, you won't include a whole file but just remove the border instead. Add <code>margin: 0;</code> to <code>.outer</code> inside <em>accordion.css</em>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.outer</span> {
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#082c42</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>; <span class="hljs-comment">/* newly added */</span>
}
</code></pre>
<p>Another browser-applied border that makes things look wrong is <code>margin-top</code> on <code>.hide</code>. Set this to 0, too:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.hide</span> {
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">50px</span>;
    <span class="hljs-attribute">display</span>: none;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">0</span>; <span class="hljs-comment">/* newly added */</span>
}
</code></pre>
<p>As you can see, you set the margin of <code>.outer</code> to 0 and when the text is closing it doesn't skip anymore. You also broke design, but that's easily fixable. Add a little padding at the bottom of <code>.outer</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.outer</span> {
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">50px</span>;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#082c42</span>;
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>; <span class="hljs-comment">/* newly added */</span>
}
</code></pre>
<p>Now you created another problem. Because of the padding, the line on the left side doesn't end with the last bullet. Padding should be applied for all the bullets except for the last one. You can find the last tab with <code>:last-child</code> and apply 0 padding at the bottom of its child <code>.outer</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.tab</span><span class="hljs-selector-pseudo">:last-child</span> <span class="hljs-selector-class">.outer</span>{
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>And this is it! Here's your pretty accordion:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613727826763/QiYv0UM1j.png" alt="finnished.png" /></p>
<blockquote>
<p>In a real application, you'd probably want to use a CSS Reset file like <a target="_blank" href="https://github.com/murtaugh/HTML5-Reset/blob/master/assets/css/reset.css">this one</a> or maybe a <a target="_blank" href="https://github.com/vladocar/CSS-Mini-Reset/blob/master/CSS-Mini-Reset.css">simpler one</a>.</p>
</blockquote>
<h2 id="conclusion">Conclusion</h2>
<p>You have a pretty accordion to show, but you also learned so many things that you can use anywhere.
You learned:</p>
<ul>
<li>How to combine <code>::before</code> and <code>::after</code> to create a beautiful effect</li>
<li>How to toggle class</li>
<li>How to apply different style by adding a class with JS</li>
<li>How to toggle hidden/shown content</li>
<li>That sometimes browsers break your design by applying their own</li>
</ul>
<p>I hope you'll be able to create many more beautiful things with the knowledge you gained in this tutorial.</p>
<p>Whole code is visible <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/pretty-accordion">here</a></p>
<blockquote>
<p>Text taken from: https://www.rasmussen.edu/degrees/technology/blog/why-learn-to-code/</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[RegEx by example (Python)]]></title><description><![CDATA[Introduction
Regular Expression or RegEx for short is a tiny language that allows you to search matches in strings.
In Python, it is accessible through the re module. 
Using it, you can check if the string is in the correct format, if the string cont...]]></description><link>https://girlthatlovestocode.com/regex</link><guid isPermaLink="true">https://girlthatlovestocode.com/regex</guid><category><![CDATA[Python 3]]></category><category><![CDATA[Python]]></category><category><![CDATA[Regex]]></category><category><![CDATA[womenwhocode]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Thu, 11 Feb 2021 08:46:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032647899/omS220wm7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Regular Expression or RegEx for short is a tiny language that allows you to search matches in strings.
In Python, it is accessible through the <code>re</code> module. 
Using it, you can check if the string is in the correct format, if the string contains some characters, extract only part of a long string,...</p>
<p>With a combination of metacharacters and literal characters, you concatenate a pattern used for search inside a string.</p>
<p><em>re</em> module provides multiple different ways for searching for a pattern in a string.</p>
<ol>
<li><p>re.match()
Searches for a pattern at the beginning of the string and returns the first occurrence. It returns a match object if a pattern appears at the beginning of the string or <code>None</code> if there is no match at the beginning.</p>
</li>
<li><p>re.search()
Searches for a pattern through the whole string and returns the first occurrence. It returns a match object if a pattern appears anywhere in the string or <code>None</code> if there is no match.</p>
</li>
<li><p>re.findall()
Searches for all occurrences of the pattern in the whole string. It returns a list of all matches.</p>
</li>
</ol>
<blockquote>
<p>Syntax for RegEx is quite extensive. I don't provide a cheatsheet in this post, you can read through <a target="_blank" href="https://www.activestate.com/wp-content/uploads/2020/03/Python-RegEx-Cheatsheet.pdf">this one</a> for more in-depth knowledge of the syntax</p>
</blockquote>
<h2 id="what-will-you-learn">What will you learn?</h2>
<p>We will go through some common cases of using RegEx:</p>
<ol>
<li>Numbers<ol>
<li>Percents</li>
<li>Decimals</li>
<li>Amounts</li>
</ol>
</li>
<li>Emails<ol>
<li>Correct format</li>
<li>Extracting part of an email</li>
</ol>
</li>
<li>Passwords<ol>
<li>Password strength errors</li>
<li>Password validation</li>
</ol>
</li>
<li>Date</li>
</ol>
<blockquote>
<p>Examples in this blog are not optimized and do not cover edge cases.
Covering edge cases and optimization hurts readability and makes it harder to learn regex.</p>
</blockquote>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>basic knowledge of Python</li>
</ul>
<h2 id="numbers">Numbers</h2>
<h3 id="percents">Percents</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_percents</span>(<span class="hljs-params">string</span>):</span>
    percent_pattern = <span class="hljs-string">r'[0-9]+%'</span>

    percents = re.findall(percent_pattern, string)

    <span class="hljs-keyword">return</span> percents
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032668418/MyTon5rZ7.png" alt="get_percents.png" /></p>
<p>Searching for a percent pattern is one of the easiest. You search for at least one digit (it may be more) followed by a <code>%</code> sign.</p>
<pre><code class="lang-python"><span class="hljs-string">"74% of girls express a desire for a career in STEM fields."</span> =&gt; [<span class="hljs-string">"74%"</span>]
<span class="hljs-string">"A whopping 80% of those in the field are male, while only 20% are female."</span> =&gt; [<span class="hljs-string">"80%"</span>, <span class="hljs-string">"20%"</span>]
</code></pre>
<blockquote>
<p>This works only for integers. If you want to catch also decimal numbers, you need to combine it with RegEx for decimals.</p>
</blockquote>
<h3 id="decimals">Decimals</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re <span class="hljs-comment"># import regex module</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_decimals</span>(<span class="hljs-params">string</span>):</span>
    decimal_pattern = <span class="hljs-string">r'[0-9]+[.,][0-9]+'</span>

    decimal_numbers = re.findall(decimal_pattern, string)

    <span class="hljs-keyword">return</span> decimal_numbers
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032685818/OJTiuSfEH.png" alt="get_decimals.png" /></p>
<p>Decimals look a little more complicated, but the basic idea is the same.
You look for at least one digit, followed by either <code>.</code> or a <code>,</code> followed by at least one digit.</p>
<pre><code class="lang-python"><span class="hljs-string">"The number π is approximately equal to 3.14159."</span> =&gt; [<span class="hljs-string">"3.14159"</span>]
<span class="hljs-string">"Niger: 7.03 children born/woman; Angola: 5.49 children born/woman; Madagascar: 4.36 children born/woman;"</span> =&gt;  [<span class="hljs-string">"7.03"</span>, <span class="hljs-string">"5.49"</span>, <span class="hljs-string">"4.36"</span>]
</code></pre>
<h3 id="amounts">Amounts</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_amount</span>(<span class="hljs-params">string</span>):</span>
    amount_pattern = <span class="hljs-string">r'[0-9]+[.,]*[0-9]*[ ]*[€$]'</span>

    amounts = re.findall(amount_pattern, string)

    <span class="hljs-keyword">return</span> amounts
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032702106/b6csG07uZ.png" alt="get_amount.png" /></p>
<p>Considering many different styles, searching for an amount can be complicated. Here we checked for a basic example.
At least one number (can be a decimal or integer) and a € or a $ sign at the end - they may be separated with space.</p>
<pre><code class="lang-python"><span class="hljs-string">"In 2018, women in the US receive 250$ less than men when it comes to software development jobs."</span> =&gt; [<span class="hljs-string">"250$"</span>]
<span class="hljs-string">"Computer: 2600€, Mouse: 7.99 €, Screen: 99,9€"</span> =&gt; [<span class="hljs-string">"2600€"</span>, <span class="hljs-string">"7.99 €"</span>, <span class="hljs-string">"99,9€"</span>]
</code></pre>
<h2 id="email">Email</h2>
<h3 id="valid-email">Valid email</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_email_format</span>(<span class="hljs-params">email</span>):</span>

    email_pattern = <span class="hljs-string">r'\S+@\S+\.\S+'</span>

    <span class="hljs-comment"># \S+ at least one char (greedy)</span>
    <span class="hljs-comment"># @, .  - exact match</span>

    <span class="hljs-keyword">if</span> re.match(email_pattern, email):
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>

    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032717758/iG0tZg0Bj.png" alt="check_email_format.png" /></p>
<p>This is a very simple email check. You check if there are any amount of non-whitespace characters that are broken by <code>@</code> and a <code>.</code>
<code>$%&amp;#$@123.#</code> would also be valid with this check.</p>
<pre><code class="lang-python"><span class="hljs-string">"john@doe.com"</span> =&gt; <span class="hljs-literal">True</span>
<span class="hljs-string">"%#$@1.2"</span> =&gt; <span class="hljs-literal">True</span>
<span class="hljs-string">"python.org"</span> =&gt; <span class="hljs-literal">False</span>
</code></pre>
<h3 id="improved-valid-email">Improved valid email</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_email_format_improved</span>(<span class="hljs-params">email</span>):</span>

    email_pattern_improved = <span class="hljs-string">r'[a-z0-9.]+@[a-z0-9]+\.[a-z]+'</span>

    <span class="hljs-keyword">if</span> re.match(email_pattern_improved, email):
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032731883/lZPwhHZQn.png" alt="check_email_format_improved.png" /></p>
<p>Here you make stronger requirements. You want either lowercase characters or numbers ("gir1cod3") that are followed by <code>@</code>,
followed by lowercase characters or numbers ("@gmai1"), a dot, and at least one lowercase character (".com").</p>
<pre><code class="lang-python"><span class="hljs-string">"john@doe.com"</span> =&gt; <span class="hljs-literal">True</span>
<span class="hljs-string">"%#$@1.2"</span> =&gt; <span class="hljs-literal">False</span>
<span class="hljs-string">"python.org"</span> =&gt; <span class="hljs-literal">False</span>
</code></pre>
<h3 id="get-the-recipient">Get the recipient</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_recipient_from_mail</span>(<span class="hljs-params">email_recipient</span>):</span>
    recipient_pattern = <span class="hljs-string">r'([a-z0-9.]+)@[a-z0-9]+\.[a-z]+'</span>

    recipients = re.findall(recipient_pattern, email_recipient)

    <span class="hljs-keyword">return</span> recipients
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032746107/S2KCwy7_Q.png" alt="get_recipient_from_mail.png" /></p>
<p>The pattern for a recipient is very similar to the improved valid email pattern. The only difference is, we added brackets <code>()</code>.
If we include brackets, we're extracting only the part of the match inside the brackets. But we still need the whole match.</p>
<pre><code class="lang-python"><span class="hljs-string">"We got an answer from python@python.org that was sent to john@doe.com"</span> =&gt; [<span class="hljs-string">"python"</span>, <span class="hljs-string">"john"</span>]
<span class="hljs-string">"We got a reply from most of the emails: python@python.org, john@doe.com. But we haven't got an answer from idontreply@whatever.com."</span> =&gt; [<span class="hljs-string">"python"</span>, <span class="hljs-string">"john"</span>, <span class="hljs-string">"idontreply"</span>]
</code></pre>
<h2 id="passwords">Passwords</h2>
<h3 id="password-strength">Password strength</h3>
<p>You know when you get those annoying little messages, what you additionally need to put in your password because the current one is not strong enough?
This is how you can do it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">password_check_parts</span>(<span class="hljs-params">password</span>):</span>
    uppercase_pattern = <span class="hljs-string">r'[A-Z]'</span>
    lowercase_pattern = <span class="hljs-string">r'[a-z]'</span>
    number_pattern = <span class="hljs-string">r'[0-9]'</span>
    special_pattern = <span class="hljs-string">r'[@#$%^&amp;+=!.]'</span>

    errors = []
    valid = <span class="hljs-literal">False</span>

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> re.search(uppercase_pattern, password): <span class="hljs-comment"># used search, because it can be anywhere in the string, match looks only at the beginning</span>
        errors.append(<span class="hljs-string">"Use at least one uppercase char"</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> re.search(lowercase_pattern, password):
        errors.append(<span class="hljs-string">"Use at least one lowercase char"</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> re.search(number_pattern, password):
        errors.append(<span class="hljs-string">"Use at least one number"</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> re.search(special_pattern, password):
        errors.append(<span class="hljs-string">"Use at least one special character"</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> errors:
        valid = <span class="hljs-literal">True</span>

    <span class="hljs-keyword">return</span> valid, errors
</code></pre>
<p>Here we have bunch of simple patterns, each one checking just for one thing. That way you know exactly what's missing in the provided password, not just that "something's wrong".</p>
<ul>
<li><code>[A-Z]</code> =&gt; any uppercase character</li>
<li><code>[a-z]</code> =&gt; any lowercase character</li>
<li><code>[0-9]</code> =&gt; any digit</li>
<li><code>[@#$%^&amp;+=!.]</code> =&gt; any character in the set; if the user uses <code>*</code> as their special character, this is gonna fail;</li>
</ul>
<pre><code class="lang-python"><span class="hljs-string">"something"</span> =&gt; (<span class="hljs-literal">False</span>, [<span class="hljs-string">'Use at least one uppercase char'</span>, <span class="hljs-string">'Use at least one number'</span>, <span class="hljs-string">'Use at least one special character'</span>])
<span class="hljs-string">"somethinG1"</span> =&gt; (<span class="hljs-literal">False</span>, [<span class="hljs-string">'Use at least one special character'</span>])
<span class="hljs-string">"12tesT3#"</span> =&gt; (<span class="hljs-literal">True</span>, [])
</code></pre>
<h3 id="valid-password">Valid password</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re <span class="hljs-comment"># import regex module</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">password_valid</span>(<span class="hljs-params">password</span>):</span>
    <span class="hljs-comment"># at least one uppercase char, at least one lower case character, at least one number, at least one special char,</span>

    <span class="hljs-comment"># password_pattern = "[A-Za-z0-9@#$%^&amp;+=]{8,}"</span>

    password_pattern = <span class="hljs-string">r'(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@#$%^&amp;+=!.])'</span>

    <span class="hljs-keyword">if</span> re.match(password_pattern, password):
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>This regex is the hardest to understand in the whole post.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032758654/2IGeBMMYy.png" alt="single_lookahead_explained.png" /></p>
<p><code>(?=</code> creates a Lookahead.
Lookahead means that although it checks if the pattern in the Lookahead brackets follows the current position of the regex engine.
This part checks only immediately behind the regex engine's position.
If you want it to look further, you have to add 'binoculars'. You do that by adding <code>.*</code>.
That means that between the current position of the regex engine and the part that matches the pattern, can be any amount of any characters (including 0 or just whitespace).
When putting all the searched patterns inside the Lookahead brackets, the regex engine doesn't move.
It just checks if can see all the Lookahead patterns somewhere.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032776633/BF7FcqPBl.png" alt="password_valid.png" /></p>
<pre><code class="lang-python"><span class="hljs-string">"Something123!"</span> =&gt; <span class="hljs-literal">True</span>
<span class="hljs-string">"1tEsT@"</span> =&gt; <span class="hljs-literal">True</span>
<span class="hljs-string">"#$%#1"</span> =&gt; <span class="hljs-literal">False</span>
</code></pre>
<h2 id="date">Date</h2>
<h3 id="valid-date">Valid date</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> re

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_date_format</span>(<span class="hljs-params">date</span>):</span>
    date_pattern = <span class="hljs-string">r'[0-9]{4}-[0-9]{2}-[0-9]{2}'</span>

    <span class="hljs-keyword">if</span> re.match(date_pattern, date):
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613032790623/xg9ZrnhIC.png" alt="check_date_format.png" /></p>
<p>We're looking for 4 numbers (year), 2 numbers (month), and 2 numbers (day), divided by <code>-</code>.
The number in curly braces <code>{}</code> tells us exactly how many occurrences we want.</p>
<pre><code class="lang-python"><span class="hljs-string">"2020-11-05"</span> =&gt; <span class="hljs-literal">True</span>
<span class="hljs-string">"20-01-05"</span> =&gt; <span class="hljs-literal">False</span>
</code></pre>
<blockquote>
<p>Some text I used for examples, was taken from https://techjury.net/blog/women-in-technology-statistics/</p>
</blockquote>
<h2 id="conclusion">Conclusion</h2>
<p>The possibilities of using RegEx are almost limitless, here we covered only a few basic cases.
Googling for the patterns usually gives you either very basic examples that help you nothing or complicated patterns you can copy, but can't understand.
The patterns we created are not fireproof, rather they are meant to help you understand the idea behind regex.</p>
<p>After going through the examples you should be able to understand RegEx that was written by someone else, create your own, and improve our examples.</p>
<p>Photo by Skies &amp; Scopes on Unsplash</p>
]]></content:encoded></item><item><title><![CDATA[CSS specificity - What overwrites what]]></title><description><![CDATA[Introduction
We access elements we want to style in different ways, depending on what we want to style.
Tags for general styling, classes for a group of elements, and IDs for single elements.
But sometimes we need to overwrite a particular set of ele...]]></description><link>https://girlthatlovestocode.com/css-specificity-what-overwrites-what</link><guid isPermaLink="true">https://girlthatlovestocode.com/css-specificity-what-overwrites-what</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[frontend]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 27 Jan 2021 10:52:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734339088/g63C20FZK.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>We access elements we want to style in different ways, depending on what we want to style.
Tags for general styling, classes for a group of elements, and IDs for single elements.
But sometimes we need to overwrite a particular set of elements and it's useful to know how to target them as best as we can.</p>
<p>Sometimes you'll need to overwrite something that you don't have a complete view of (eg. spaghetti code in a large team) or complete access to (eg. bought WordPress theme).
Developers usually tackle this by adding <code>!important</code>.
That is <strong>not</strong> a good idea.</p>
<p><code>!important</code> should only be used as a last resort.</p>
<p>At first, you have just one <code>!important</code>, then you write another one, to overwrite the previous one and so on and on.
Try to force your CSS to be applied differently - by knowing the specificity rules.</p>
<p>Specificity rules are a way that the browser decides which of the conflicting CSS rules pointing to the same element will apply.</p>
<p>Here you have a graph, displaying specificity rules.
On the left, there are rules depending on a selector (eg. tag, ID).
On the right, there are rules, based on where the CSS style is applied.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734490254/tGCgo4G9r.png" alt="all_specifity.png" /></p>
<p>At the top, they don't impact one another.
However, when you start applying CSS rules inline, it collides with selector-applied rules.
CSS applied inline, has higher specificity than the one, applied by any ID.</p>
<p>Below, I'll do a review example for each of the cases, so you can check it yourself.
Each time, I'll compare 2 adjacent selectors/CSS positions.</p>
<blockquote>
<p>Colors on the graph correspond with the assigned text color. Selectors and CSS usage colored gray, are not included in the comparison.</p>
</blockquote>
<h2 id="based-on-the-selector">Based on the selector</h2>
<p>You probably know that style, applied by <code>ID</code> overwrites style applied with <code>class</code> or <code>tag</code>.
And that <code>!important</code> rules them all.</p>
<p>But there are few other rules mixed in-between. For example, a more extensively defined rule trumps the more basic one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734508335/ppDmGPuZ1.png" alt="selector_based.png" /></p>
<p>We will compare CSS selectors, listed bellow:</p>
<ol>
<li><strong>tag</strong> vs. <strong>class</strong></li>
<li><strong>1 class</strong> vs. <strong>2 classes on the same element</strong></li>
<li><strong>2 classes on the same element</strong> vs. <strong>parent class + child class</strong></li>
<li><strong>parent class + child class</strong> vs. <strong>ID</strong></li>
<li><strong>ID</strong> vs. <strong>parentID + child class</strong></li>
<li><strong>parent ID + child class</strong> vs. <strong>parent ID + child ID</strong></li>
<li><strong>class with !important</strong> vs. <strong>parent ID + child ID</strong></li>
<li><strong>class with !important</strong> vs. <strong>ID with !important</strong></li>
</ol>
<hr />

<h3 id="tag-vs-class">tag vs. class</h3>
<p>Tags are the easiest to overwrite.</p>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"class-over-tag"</span>&gt;</span>The 1st algorithm which was ever processed by a machine was written by the legend Ada Lovelace.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.class-over-tag</span> {
    <span class="hljs-attribute">color</span>: darkgreen;
}

<span class="hljs-selector-tag">div</span> {
    <span class="hljs-attribute">color</span>: brown;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734585967/I_njzpcdA.png" alt="tag_vs_class.png" /></p>
<hr />

<h3 id="1-class-vs-2-classes-on-the-same-element">1 class vs. 2 classes on the same element</h3>
<p>More classes on the same element have a higher specificity than just a single class.</p>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"one-class another-class"</span>&gt;</span>Ever played Assasin’s Creed? If you have, you will be surprised to know that the producer of Assassin’s Creed is a programmer, Jade Raymond.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.one-class</span><span class="hljs-selector-class">.another-class</span> {
    <span class="hljs-attribute">color</span>: darkblue;
}

<span class="hljs-selector-class">.one-class</span> {
    <span class="hljs-attribute">color</span>: darkgreen;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734608264/gXp6L_H3l.png" alt="1class_vs_2class.png" /></p>
<hr />

<h3 id="2-classes-on-the-same-element-vs-parent-class-child-class">2 classes on the same element vs. parent class + child class</h3>
<p>2 classes on the same element have the same specificity as the class on the parent and the class on the child.
That means the latter one overwrites the previous one.
Here you can see both options:</p>
<p><strong>CODE A</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"parent-class"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child-class second-child-class"</span>&gt;</span>Sara Haider is currently working as a software engineer at Twitter. Known for her programming skills, Sara specializes in Android App development.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.child-class</span><span class="hljs-selector-class">.second-child-class</span> {
    <span class="hljs-attribute">color</span>: darkblue;
}

<span class="hljs-selector-class">.parent-class</span> <span class="hljs-selector-class">.child-class</span> {
    <span class="hljs-attribute">color</span>: lightgreen;
}
</code></pre>
<p><strong>RESULT A</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734632795/GuHVUt3p6.png" alt="2class_vs_parent_child_class.png" /></p>
<p><strong>CODE B</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"parent-class"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child-class second-child-class"</span>&gt;</span>Sara Haider is currently working as a software engineer at Twitter. Known for her programming skills, Sara specializes in Android App development.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.parent-class</span> <span class="hljs-selector-class">.child-class</span> {
    <span class="hljs-attribute">color</span>: lightgreen;
}

<span class="hljs-selector-class">.child-class</span><span class="hljs-selector-class">.second-child-class</span> {
    <span class="hljs-attribute">color</span>: darkblue;
}
</code></pre>
<p><strong>RESULT B</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734654953/iZfAeUoeV.png" alt="2class_vs_parent_child_class_second_variant.png" /></p>
<hr />

<h3 id="parent-class-child-class-vs-id">parent class + child class vs. ID</h3>
<p>Selecting an element directly by ID has a higher priority than combining parent and child class (or two classes on the said element).</p>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"parent-class"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child-class"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"parent-child-vs-id"</span>&gt;</span>Corrinne Yu is known for her contribution to some famous games like Borderlands, Zombie, Unreal Engine 3 and Brothers in arms. Her most famous work is her contribution to the 2012 smash-hit game, Halo 4. She has also won a national award in 2009 for Nuclear Physics research.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-id">#parent-child-vs-id</span> {
    <span class="hljs-attribute">color</span>: lightblue;
}  

<span class="hljs-selector-class">.parent-class</span> <span class="hljs-selector-class">.child-class</span> {
    <span class="hljs-attribute">color</span>: lightgreen;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734681320/Qy2Z2XSkX.png" alt="parent_child_class_vs_ID.png" /></p>
<hr />

<h3 id="id-vs-parentid-child-class">ID vs. parentID + child class</h3>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"parent-id"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child-class"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"child-id"</span>&gt;</span>The reason you are addicted to iPhone games is Amanda Wixted.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-id">#parent-id</span> <span class="hljs-selector-class">.child-class</span> {
    <span class="hljs-attribute">color</span>: purple;
}

<span class="hljs-selector-id">#child-id</span> {
    <span class="hljs-attribute">color</span>: lightblue;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734705393/Xl4lL7wil.png" alt="id_vs_parent_id_child_class.png" /></p>
<hr />

<h3 id="parent-id-child-class-vs-parent-id-child-id">parent ID + child class vs. parent ID + child ID</h3>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"parent-id-1"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child-class"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"child-id-1"</span>&gt;</span>Tracy Chou is the finest example of how good can females are at diverse programming needs.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-id">#parent-id-1</span> <span class="hljs-selector-id">#child-id-1</span> {
    <span class="hljs-attribute">color</span>: deeppink;
}

<span class="hljs-selector-id">#parent-id-1</span> <span class="hljs-selector-class">.child-class</span> {
    <span class="hljs-attribute">color</span>: purple;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734728842/i2xSUpB-q.png" alt="parent_id_child_class_vs_parent_id_child_id.png" /></p>
<hr />

<h3 id="class-with-important-vs-parent-id-child-id">class with !important vs. parent ID + child ID</h3>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"parent-id-2"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"important-class"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"child-id-2"</span>&gt;</span>
        Ada has the honor of being the first programmer in the world but other woman programmers are not far behind.
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.important-class</span> {
    <span class="hljs-attribute">color</span>: orange<span class="hljs-meta">!important</span>;
}
<span class="hljs-selector-id">#parent-id-2</span> <span class="hljs-selector-id">#child-id-2</span> {
    <span class="hljs-attribute">color</span>: deeppink;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734754527/WTIz2hUJq.png" alt="class_important_vs_parent_child_id.png" /></p>
<hr />

<h3 id="class-with-important-vs-id-with-important">class with !important vs. ID with !important</h3>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"important-id"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"important-class"</span>&gt;</span>Programming is a fascinating career option in today’s world. It has mystery, glamor, and money provided you do hard work to achieve the best.
    However, it is a field dominated by males. Though, there are many female programmers who have made names for themselves.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p><code>CSS</code></p>
<pre><code class="lang-css"><span class="hljs-selector-id">#important-id</span> {
    <span class="hljs-attribute">color</span>: yellow <span class="hljs-meta">!important</span>;
}
<span class="hljs-selector-class">.important-class</span> {
    <span class="hljs-attribute">color</span>: orange <span class="hljs-meta">!important</span>;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734777889/5fztIry-M.png" alt="classimportant_vs_idimportant.png" /></p>
<p></p><hr /><p></p>
<hr />

<h2 id="based-on-the-usage-of-css">Based on the usage of CSS</h2>
<p>CSS specificity based on where did we included our style is pretty straightforward:</p>
<ul>
<li><strong>inline style</strong> is the strongest</li>
<li><strong>internal style</strong> beats included style</li>
<li>if both styles are included the same way, the <strong>latter</strong> one prevails</li>
</ul>
<p>Unless you have a good reason, I don't suggest you use inline or internal style.
If you want to have your code clean and neat, always write your styling rules in separated CSS files.
It's still good to know how this works.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734800815/6ERn5JZBZ.png" alt="position_style.png" /></p>
<p>We will compare CSS usages, listed bellow:</p>
<ol>
<li><strong>2 included stylesheets</strong></li>
<li><strong>included</strong> stylesheet vs. <strong>internal</strong> style</li>
<li><strong>internal</strong> style vs. <strong>inline</strong> style</li>
<li><strong>inline</strong> style vs. <strong>ID</strong></li>
<li><strong>inline</strong> style vs. <strong>ID wih <code>!important</code></strong></li>
</ol>
<h3 id="2-included-stylesheets">2 included stylesheets</h3>
<p>When both styles are included the same way, the latter one prevails.
In this case, we use 2 external stylesheets.
In the first one, we set the text color to 'green' and that gets overwritten by the second stylesheet, which sets the text color to 'blue'.
As you can see in the image below, the text is blue.
But in the first stylesheet, we also set a green, 2px wide border.
In the second stylesheet, we do nothing to change that, so the border style from the first file is used.</p>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style1.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style2.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"included-style"</span>&gt;</span>
    Grace Murray Hopper was one of the first programmers of the Harvard Mark I computer. She invented the first compiler for a computer programming language and the one of those who popularized the idea of machine-independent programming languages.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><code>style1.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.included-style</span> {
    <span class="hljs-attribute">color</span>: green;
    <span class="hljs-attribute">border</span>: solid green <span class="hljs-number">2px</span>;
}
</code></pre>
<p><code>style2.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.included-style</span> {
    <span class="hljs-attribute">color</span>: blue;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734834929/ctFmQsw6q.png" alt="includedstyleswithborder.png" /></p>
<h3 id="included-stylesheet-vs-internal-style">Included stylesheet vs. internal style</h3>
<p>If we include a CSS file, we can easily overwrite its rules with the internal style, that is written in the <code>&lt;head&gt;</code> section of our HTML file.
In the included stylesheet, we set the text to blue, but we overwrite this inside the <code>&lt;style&gt;</code> tags and we set it to red.</p>
<p><strong>CODE</strong></p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style1.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style2.css"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-class">.included-vs-internal</span> {
            <span class="hljs-attribute">color</span>: red;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"included-vs-internal"</span>&gt;</span>
    Lois Mitchell Habit was one of the ten-person team at IBM that developed FORTRAN, the first successful high-level programming language.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><code>style2.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.included-vs-internal</span> {
    <span class="hljs-attribute">color</span>: blue;
}
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611734853694/XLTPOZC2X.png" alt="internal_style.png" /></p>
<h3 id="internal-style-vs-inline-style">internal style vs. inline style</h3>
<p>The most powerful way to use some style is to write it <code>inline</code>. That means you write it directly on the element.
The only way, you can overwrite that rule, is by <code>!important</code>.
That means that inline style with added <code>!important</code> is <strong>impossible to overwrite</strong>.
You should use inline styles with caution, otherwise, you can create a big mess.</p>
<p>Here we set the text color to red, but with an inline style, we changed it to orange.</p>
<p><strong>CODE</strong>
<code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-class">.internal-vs-inline</span> {
            <span class="hljs-attribute">color</span>: red;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"internal-vs-inline"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color: orange"</span>&gt;</span>
    Barbara Liskov (Born 7 Nov 1939) is one of the first women to be granted a doctorate in computer science in the United States and is a Turing Award winner who developed the Liskov substitution principle.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611742722715/3VbwH3iQU.png" alt="inlinestyle.png" /></p>
<h3 id="inline-style-vs-id">Inline style vs. ID</h3>
<p>Inline style is also able to overwrite the <code>ID</code>.
If we set the text color to light blue with the <code>ÌD</code> selector and then add <code>color: orange</code> as an inline style, our text will be orange.</p>
<p><strong>CODE</strong>
<code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-id">#not-stonger-id</span> {
            <span class="hljs-attribute">color</span>: lightblue;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"not-stonger-id"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color: orange"</span>&gt;</span>
    Frances Elizabeth Allen was the first female IBM Fellow and in 2006 became the first woman to win the Turing Award.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><strong>RESULT</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611742742159/fhikex6e9.png" alt="vsID.png" /></p>
<h3 id="inline-style-vs-important">Inline style vs. <code>!important</code></h3>
<p>However, if add <code>!important</code> to the rule, written as internal CSS, that will prevail before the inline style.</p>
<p>Code is almost the same, we only added <code>!important</code>... :</p>
<p><strong>CODE</strong>
<code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-id">#not-stonger-id</span> {
            <span class="hljs-attribute">color</span>: lightblue <span class="hljs-meta">!important</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"not-stonger-id"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color: orange"</span>&gt;</span>
    Frances Elizabeth Allen was the first female IBM Fellow and in 2006 became the first woman to win the Turing Award.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><strong>RESULT</strong>
...but as you can see, the result is different:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611742762888/NMVEu2rEI.png" alt="important.png" /></p>
<h2 id="conclusion">CONCLUSION</h2>
<p>In this post, you got to knew the rules, by which CSS is applied and its specificity.
That way, next time you'll be able to avoid adding <code>!important</code> when your CSS is not behaving as you expect it to.
Not only that, you'll understand why it behaves the way it does and you'll be able to fix it.</p>
<blockquote>
<p>The text used as a placeholder in the HTML was taken from:
<a target="_blank" href="https://www.techworm.net/2016/10/worlds-top-5-famous-female-programmers.html">techworm</a> and <a target="_blank" href="https://www.technotification.com/2018/05/top-10-female-programmers.html">technotification</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Help! I need some motivation.]]></title><description><![CDATA[There are so many tips on how to be productive and motivated. 
Here I listed some of the things that are working for me.
You don't need to follow all of them. What works for someone, maybe won't work for you, so feel free to cherry-pick.
At the botto...]]></description><link>https://girlthatlovestocode.com/help-i-need-some-motivation</link><guid isPermaLink="true">https://girlthatlovestocode.com/help-i-need-some-motivation</guid><category><![CDATA[motivation]]></category><category><![CDATA[Experience ]]></category><category><![CDATA[planning]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 13 Jan 2021 14:10:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546424884/E0Mu-j01p.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are so many tips on how to be productive and motivated. 
Here I listed some of the things that are working for me.
You don't need to follow all of them. What works for someone, maybe won't work for you, so feel free to cherry-pick.</p>
<p>At the bottom, you'll find two exercises I derived from some psychotherapeutic exercise.
They won't work miracles, but doing them in depth should help you improve your motivation and your planning ability.</p>
<p>We're prone to making easily achievable decisions faster and decisions we have to make an effort slower.
So you want to make the wanted decisions easy to achieve and the decisions you don't want to make as hard as possible.</p>
<h2 id="limit-the-need-for-making-good-choices">Limit the need for making good choices</h2>
<p><strong>Limit the time you spend making decisions.</strong>
You can achieve that by erasing the choices that are the same every day ("I'm going to start to work <strong>now</strong>").
You achieve that by sticking to the routine.
There are some choices, that can't be routine. They are different every time ("I'm going to work on <em>that</em> project").
You save yourself some time and nerves by <strong>planning ahead</strong>. </p>
<h3 id="routine">Routine</h3>
<p>Maintain a weekly and daily routine. 
Some things will be the same every day (waking up, breaks, start and end of a workday)</p>
<p>Where a daily routine isn't possible or it doesn't make sense to do it every day, create a weekly routine.</p>
<p>Example of a weekly routine:
Monday -&gt; working on a blog
Tuesday - Thursday -&gt; current project
Wednesday at 12.00 -&gt; staff meeting
Friday -&gt; learning new things + longer lunch break</p>
<p>Many times we're given a false impression, that sticking to a routine will be effortless.
Routine is weaker than a habit. That means sticking to a routine will still require some effort from you.
Don't get discouraged by that, just stick to your routine.</p>
<h3 id="plan-ahead">Plan ahead</h3>
<p>You have your routine down, but that's in general. You still need to know exactly what are you going to do in the days ahead.
You know you'll write a blog on Monday, but what about? You'll work on your project on Tuesday, but which part?
Have a plan in mind a week ahead (I'm having a meeting on Thursday, I'll push to production on Tuesday...).
Just before you finish your work for today (not after that!), go through a plan for tomorrow.</p>
<p>If you'll sit down on your chair tomorrow and only then started thinking about what you're actually going to do, you'll lose so much energy.
Worst case, you'll glide from one task to another and accomplish nothing.</p>
<p>Your plan has to be so clear that you can sit down in front of your computer and start right away.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546786459/61df1UlLN.jpeg" alt="dad-hotel-BaeQcvUkwWg-unsplash.jpg" /></p>
<h2 id="make-unwanted-choices-harder-to-make">Make unwanted choices harder to make</h2>
<p>You start coding, decided to do a lot today, and after 7 minutes a notification pings.
Either you'll check whatever notification or you'll keep wondering if it's something interesting.
Either way, you lose focus.</p>
<p>You get to a though /boring task and you check social media, just for a second.
Maybe you keep checking your emails in case it will be something important.
You lose focus.</p>
<p>You make those decisions effortlessly. 
Maybe the tab is already open, the mobile phone is unlocked by the touch of your index finger...
<strong>Make those decisions harder.</strong></p>
<p>Leave your phone in another room (preferably upstairs). You're too lazy to go upstairs just for the sake of checking your notifications.
Or turn it off. It takes forever for it to turn on, by then you'll already realize you're procrastinating.</p>
<p>Log out of social networks and mail clients. 
So used to already being logged in, you'll maybe open a Twitter page just to see you need to login and remember that that's not what you currently want.</p>
<p>If you have a basket of unfolded laundry in the same room, kick it out without hesitation.</p>
<p>If possible, don't work in the kitchen. A coffee maker and the fridge are way too close to you.
Currently, the only place I can work in is our kitchen. I drink approximately 4 freshly brewed coups of tea per hour.
I don't even want to count cookies.</p>
<h2 id="have-a-vision">Have a vision</h2>
<p>It's hard to work for something if you don't know what that <em>something</em> is.
You need to find something that <em>drives</em> you. 
If you work just for the sake of working, how will you continue when it won't be fun to work?</p>
<p>Why are you learning to code?
Why are you learning this language?
Why are you creating this program?</p>
<p>At the end of this post, you'll find two exercises that should help you create your vision.
I strongly suggest you take the time and do them because good envisioning is sometimes the only thing that keeps you going.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546726097/FiluQG8Zp.jpeg" alt="randy-tarampi-U2eUlPEKIgU-unsplash.jpg" /></p>
<h2 id="start-your-day-with-exercise">Start your day with exercise</h2>
<p>For me, a great way to start my day is <strong>going for a walk</strong>. 
Fresh air, simple movement, time to be with my thoughts.
It is also a great time to envision my goals and plan ahead.</p>
<p>But it is very time-consuming and if you don't have the time for it, you can switch it for a light exercise.
It will get your blood flowing and your body won't be nervous because of idleness.</p>
<p>There are many mobile apps that allow you to do full-body exercise in less than 10 minutes and that's a time you surely can spare.
You can also do those exercises during your <strong>smart breaks</strong>.                                                         </p>
<h2 id="smart-breaks">Smart breaks</h2>
<p><strong>Planned. Regular. Well spent.</strong></p>
<p>Don't take your break whenever you feel like it and however long as you want to.
Let them be part of your routine. Know when you are taking them and how long they should be.
Don't skip them.</p>
<p>One longer break in the mid of the day is not enough. 
The longer you go without break, the longer it will take you to get back to the start with your resources.
There is no rule on how often and how long a break you need to take. 
Experiment a little, try to find out what works for you best.</p>
<p>Most of us probably spend our breaks scrolling Twitter/FB/news. 
This might surprise you, but that's a <strong>bad idea</strong>.</p>
<p>Stand up. Refill your water cup. Try to clear your mind of current coding problems.
Stretch or do a short and light exercise. If you have time, go for a walk.</p>
<p><strong>Don't sit and don't stare at a screen.</strong>
That's what you've been doing before you took a break.</p>
<h2 id="keep-it-realistic">Keep it realistic</h2>
<p>There are not enough motivation tools in the world to enable you to finish 47 tasks a day.</p>
<p>If you're setting you're expectations too high, you're setting yourself up for disappointment.</p>
<p>If your kids are in school/kindergarten from 9 AM to 3 PM, you can't work 9 hours.
If you have a day job, you can't post a blog/long thread 5x/week.
You can't learn a new framework in a week.</p>
<p>Expecting too much from yourself will make you only do less. 
Setting realistic goals and achieving them will make you motivated.
Failing to meet your goals (almost) every time, will just make you question your ability.</p>
<p>Another side of being realistic is <strong>not</strong> having too low expectations.
If you'll reach your goals without any effort, you'll get bored.
If you'll reach your goals and nothing will change, you'll get frustrated.</p>
<p>Set <strong>good</strong> goals.
Those two exercises can help you with that. </p>
<h2 id="lessa-nameexcercisesgreaterlessagreatermotivation-exercises"><a></a>Motivation exercises</h2>
<p>Here I'm presenting two exercises that are very similar in their execution. 
One is meant for you to go over your past accomplishments and the other is meant to create a vision, goals, and a plan to achieve them.
Knowing where you came from and why are you doing what you're doing can be very motivational.</p>
<p>I advise you not to do both exercises at once. 
Take your time. 
<strong>It's not about drawing, it's about thinking.</strong></p>
<p><em>For both exercises, you'll need a piece of paper and colored pencils.</em></p>
<h3 id="river-of-codings-past">River of coding's past</h3>
<p>This exercise can help you appreciate what you already achieved. 
Too often we rush toward some goal and don't stop to 'smell the flowers'.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546085221/ehFE21-8x.jpeg" alt="motivation_river1.jpg" /></p>
<ol>
<li><p><strong>Draw a little circle on the left side of the paper</strong> for when you started your coding journey.</p>
<p> Next to it, draw a symbol that represents your beginnings.</p>
</li>
<li><p>On the right side of the paper (on whatever height you want) <strong>draw a little circle for the present moment</strong>. </p>
<p> Add a symbol that represents the current moment of your learning.</p>
</li>
<li><p><strong>Draw a line between those two points that represent your journey until now.</strong></p>
<p> If your learning was steep, let the line represents that. If you quit for a while, dot the line. 
Draw the motivation drop and when you learned something huge.</p>
</li>
<li><p><strong>Add symbols along the line for the important moments.</strong> </p>
<p> When you felt that you learned CSS. 
When you started to learn Python or felt that you mastered JS.
Whey you got your first job interview or landed your first job.
When you had to take time off coding because you got a baby.
Amazing things you created and all the projects you finished.</p>
<p> Whatever feels important to you and is somehow related to coding.
<strong>When you finish that, you should have a piece of paper that fairly represents your journey.</strong>
It should show the troubles you overcome and the new knowledge you acquired.</p>
</li>
<li><p><strong>Examine your journey and be proud of what you achieved.</strong></p>
<p>Try to remember that filling you got when you finished your first project.
Try to experience again the excitement you felt when you got that job you wanted.</p>
</li>
<li><p><strong>Put your index finger on the circle that represents <code>NOW</code>.</strong>
Close your eyes.</p>
<p> Imagine the time your learning will be over (in general; We never really stop learning). 
How will you know that you achieved your goal?
What will be different for you?
How will you feel like? 
What will it look like? 
What will you do when that time comes?</p>
<p> This is a really important part of the exercise, so <strong>don't rush</strong> through it just hastily answering the questions I provided.
Visualize it, <strong>put yourself in that moment</strong>.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546102176/HWJqkxS2K.jpeg" alt="motivation_river1_drawing.jpg" /></p>
<h3 id="river-of-codings-future">River of coding's future</h3>
<p>That exercise will help you envision your future as a developer. 
As explaining before, defining your goals is essential.
Fantasizing about your vision and goals can get you through the rough patches.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546124027/YwKUhZBcp.jpeg" alt="motivation_river2.jpg" /></p>
<ol>
<li><p>On the right side of the paper <strong>draw the Ocean of Success</strong>. 
In the ocean, draw symbols for what you want to achieve.</p>
<p> What programming languages you want to learn or be an expert at?
Do you want to be your own boss?
What is the paycheck you desire? What do you want that money for?
Do you want to start a blog, do you want to achieve a certain number of followers/readers...</p>
<p> Those are just suggestions, don't limit yourself to them.</p>
</li>
<li><p>On the left side of the paper, <strong>draw a water spring</strong>. </p>
<p> That's where you are right now. You can add a symbol that represents you at a current moment.</p>
</li>
<li><p>Between the spring and the ocean <strong>draw a river</strong> any way you want to. 
Put symbols on the river for the important parts of your plan. </p>
<p> If you want to land a FE job, you need to learn HTML/CSS/JS.
If you want a promotion, you need to learn that framework...
If you want to be your own boss you need to achieve financial stability and quit your day job.
If you want to have a certain number of readers, you need to start a blog or be more regular at posting.</p>
</li>
<li><p>Put your finger on the spring and <strong>slowly follow the stream</strong>. 
Envision the path between you and your main goal. </p>
<p> What do you have to do to get to the ocean?
How are you going to get there? 
What will be the struggles you'll have to overcome?
Try to really imagine it.</p>
</li>
<li><p><strong>Put the paper somewhere near you.</strong>
 When you achieve something that is drawn on your river, color it, mark it. </p>
<p> <strong>Be proud of yourself.</strong> 
 You're getting closer to the ocean...</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610546147450/BDKyST2wr.jpeg" alt="motivation_river2_drawing.jpg" /></p>
<h2 id="conclusion">Conclusion</h2>
<p><strong>Motivation doesn't just fall from the sky. 
Highly motivated people weren't born with it. They worked for it.</strong></p>
<p>If you feel unmotivated for some time, come back to those exercises.
See if your goals have changed. It's hard to pursue goals we no longer wish for.</p>
<p>Maybe your routine is not working for you anymore.
Or maybe you're just tired.</p>
<p>Don't judge yourself if you feel unmotivated, even though you're trying sooo hard.</p>
<p><strong>Sometimes we all need just a little rest.</strong></p>
<p><em>Images are from Unsplash. Creators: Drew Beamer, Dad hotel, Randy Tarampi.</em></p>
]]></content:encoded></item><item><title><![CDATA[Customizing <li> bullets]]></title><description><![CDATA[For a great-looking webpage, all elements need to match the design, including bullets.
By default, list styling is very limited:

While you can change its type, you can't change the color.
You can select the position of the bullet in two ways (inside...]]></description><link>https://girlthatlovestocode.com/customizing-bullets</link><guid isPermaLink="true">https://girlthatlovestocode.com/customizing-bullets</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[#beginners #learningtocode #100daysofcode]]></category><category><![CDATA[newbie]]></category><category><![CDATA[styling]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Mon, 04 Jan 2021 12:44:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1609412856521/dE0yR6fMT.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For a great-looking webpage, all elements need to match the design, including bullets.
By default, list styling is very <a target="_blank" href="https://www.w3schools.com/cssref/pr_list-style.asp">limited</a>:</p>
<ul>
<li>While you can change its <a target="_blank" href="https://www.w3schools.com/cssref/pr_list-style-type.asp">type</a>, you can't change the color.</li>
<li>You can select the position of the bullet in <a target="_blank" href="https://www.w3schools.com/cssref/pr_list-style-position.asp">two ways</a> (inside/outside), but you don't have any influence regarding pixels.</li>
<li>You can use an <a target="_blank" href="https://www.w3schools.com/cssref/pr_list-style-image.asp">image</a>, but you can't resize or change its position in any way.</li>
</ul>
<p>If you want to have a lot of freedom at styling it, you have to hide the default <code>list-style</code> and create new 'bullets' with <strong>::before</strong>.</p>
<h2 id="what-will-i-learn">What will I learn?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609412906692/9KPQ2-bET.png" alt="all.PNG" /></p>
<p>In this tutorial, we will <strong>review 5 possibilities of styling bullets</strong>:</p>
<ol>
<li>Squares</li>
<li>Triangles</li>
<li>Icons</li>
<li>Images</li>
<li>Bullets that differs</li>
</ol>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>basic HTML</li>
<li>basic CSS</li>
<li>pseudo-selector <code>::before</code> </li>
</ul>
<blockquote>
<p>If you don't feel comfortable with <code>::before</code>, I suggest you check <a target="_blank" href="https://girlthatlovestocode.com/css-pseudo-elements-before-and-after">this post</a> explaining it thoroughly.</p>
</blockquote>
<h2 id="intro">Intro</h2>
<p>All the lists are going to be <a target="_blank" href="https://www.w3schools.com/tags/tag_ul.asp">unordered lists</a>.
There will be five of them, each with a different class ('<em>square-bullets</em>', '<em>arrow-bullets</em>', '<em>icon-bullets</em>', '<em>image-bullets</em>' and '<em>different-bullets</em>').
Each <code>ul</code> will be created in its own <code>HTML</code> file (named the same as the <code>class</code> of our <code>ul</code>) and each we'll create <code>CSS</code> for it in a separated <code>.css</code> file with the same name.
In all the <code>CSS</code> we'll include a part that sets <code>list-style</code> to <code>none</code>, so the out-of-the-box list styling doesn't interfere with our creations.
Also for all the bullets will set some padding (<code>ul &gt; li {padding: 10px 25px}</code>) so our bullets have a little breathing room.</p>
<h2 id="squares">Squares</h2>
<p>Square bullets can be very useful when you want to associate each <code>&lt;li&gt;</code> element with a differently colored area.
You can create squares of different colors (we will see how to that on the last <code>ul</code>).</p>
<p>The interesting thing about square bullets is that they don't have content, they only have a background.</p>
<h3 id="html">HTML</h3>
<p>Let's first create out <code>HTML</code> file:</p>
<p><code>square.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"square.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-comment">&lt;!-- square bullets --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square-bullets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>You can style your bullets to look many different ways. For example, they can be little squares.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>In that case, they don't have content, just background.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Vestibulum consectetur, sem id venenatis pretium.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="css">CSS</h3>
<p><code>square.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}
<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.square-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#d050ff</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">12px</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>We need to create a <code>::before</code> selector on the <code>&lt;li&gt;</code> element of our first list with class <code>.square-bullets</code>.</p>
<blockquote>
<p>For creating custom bullets, it's important for you to understand <code>::before</code> pseudo-element.
If you're a little unsure about it, <a target="_blank" href="https://girlthatlovestocode.com/css-pseudo-elements-before-and-after">refresh your knowledge</a> before you continue this tutorial.</p>
</blockquote>
<p>As I already mentioned, the square bullet doesn't have content.
We select <code>width</code>, <code>height</code> and <code>background-color</code>.</p>
<p><code>::before</code> is an inline element. That means that we can't assign <code>width</code> and <code>height</code> to it.
Because it doesn't have any content and we can't set width or height to it, its default size is 0 x 0.
We have 2 options to change that:</p>
<ol>
<li>Set it as <code>display: block</code>. That way, we can set its width and height</li>
<li>Set its <code>position</code> to absolute. The elements with <code>position: absolute</code> are automatically treated as <code>display: block</code>.</li>
</ol>
<p>I prefer setting the position to absolute because it also gives me the ability to adjust the location of the <code>::before</code>.
Additionally, for the correct positioning of our absolute-positioned <code>::before</code>, we need to position its parent element - <code>&lt;li&gt;</code>.</p>
<blockquote>
<p>Absolute positioned element is positioned relative to its first positioned (not static) ancestor element (source: <a target="_blank" href="https://www.w3schools.com/">w3schools.com</a>).  </p>
</blockquote>
<p><code>position: relative</code> doesn't imediatly change elements location, so we are going to use that:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square-bullets</span> &gt; <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">position</span>: relative;
}
</code></pre>
<p>The square is covering the text and is also not aligned with the text.
We fix that with <code>left</code> and <code>top</code>.</p>
<blockquote>
<p>Not sure why we did that? Get acquainted with <a target="_blank" href="https://www.w3schools.com/css/css_positioning.asp">positioning elements</a>.</p>
</blockquote>
<p>Congratulate yourself, you just customized your first <code>ul</code>!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609412942118/EvHkvpTSd.png" alt="squares.PNG" /></p>
<h2 id="arrows">Arrows</h2>
<h3 id="html">HTML</h3>
<p><code>arrow.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"arrow.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"arrow-bullets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Arrows in place of bullets can create amazing effect for example, when creating a list of advantages of your company.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>You can create triangles any size and shape on https://triangle.designyourcode.io/ or any similar webpage.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>In sit amet ex in arcu varius eleifend ut vel turpis. Suspendisse ac vulputate libero, a suscipit risus. Vestibulum consectetur, sem id venenatis pretium, velit nisl suscipit orci, ac dictum felis orci a neque. Fusce tempor nunc et nisl accumsan, ac consequat justo elementum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi bibendum malesuada diam. Sed porta hendrerit sem eu varius. Maecenas eu est enim.
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Arrow-shaped bullets are great if you want your visitor to focus on the list.
As square bullets, arrow bullets also don't have content.
However, they are harder to create.
Thankfully, we have tools that help us create them.</p>
<p>Go to https://doodlenerd.com/css-element/css-triangle-generator and create a right triangle 16 x 16px.</p>
<p>This is the code that will generate:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.css-triangle</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">border-style</span>: solid;
    <span class="hljs-attribute">border-width</span>: <span class="hljs-number">8px</span> <span class="hljs-number">0</span> <span class="hljs-number">8px</span> <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">border-color</span>: transparent transparent transparent <span class="hljs-number">#000000</span>;
}
</code></pre>
<p><strong>Change the selector to <code>arrow-bullets &gt; li::before</code></strong></p>
<p>Check the <code>border-color</code>. That's the property that creates the triangle. The first three are transparent, the last one is color.
If you want to change the color of the triangle, you change the last parameter (<em>#000000</em>).</p>
<p>If you check your browser, you will see - <strong>nothing</strong>.
Inspect the element - you will see the <code>&lt;li&gt;</code> element, but no <code>::before</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609412979328/qPdk27Pk2.png" alt="noBefore.PNG" /></p>
<p>That's because the generator created a triangle that exists as an element, not as a pseudo-element.
All pseudo-elements need to have <code>content</code>, even if it's empty.
And because in this case, it's empty, we need to add <code>position: absolute</code> to a <code>::before</code> and <code>position: relative</code> to <code>li</code> as in the case with squares.
Because positioning is a little off, we add the same <code>top</code> and <code>left</code> values as before.</p>
<p>This is the css you should have:
<code>arrow.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.arrow-bullets</span> &gt; <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.arrow-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">border-style</span>: solid;
    <span class="hljs-attribute">border-width</span>: <span class="hljs-number">8px</span> <span class="hljs-number">0</span> <span class="hljs-number">8px</span> <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">border-color</span>: transparent transparent transparent <span class="hljs-number">#00fa9a</span>;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">12px</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>And this is the result you should see by now:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413009036/HOXTF37n3.png" alt="triangles.PNG" /></p>
<h2 id="icon-bullets">Icon bullets</h2>
<p>Sometimes you want your bullets to communicate something along with the text.
That's when you change your bullets to icons (eg. you could use the 'i' icon when you're giving information) </p>
<p>We are going to use Font Awesome icons, so we'll have to include them in our HTML file.</p>
<blockquote>
<p>If you want to use your Font Awesome link, follow <a target="_blank" href="https://fontawesome.com/start">these instructions</a>.</p>
</blockquote>
<h3 id="html">HTML</h3>
<p><code>icon.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://kit.fontawesome.com/d465826c4f.js"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"icon.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"icon-bullets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Sometimes you want to emphasize what this list is about and that's when it's great to have icons instead of bullets.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>For example, this list talks about code, that's why we used file code icon. <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Suspendisse ac vulputate libero, a suscipit risus.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>I choose <a target="_blank" href="https://fontawesome.com/icons/file-code?style=solid">'code'</a> icon, but you can choose something else <a target="_blank" href="https://fontawesome.com/icons?d=gallery">here</a>.</p>
<p><code>icon.css</code></p>
<pre><code><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.icon-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Font Awesome 5 Free"</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f1c9"</span>;
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">left</span>: -<span class="hljs-number">9px</span>;
}
</code></pre><p>We have to specify font-family as <code>Font Awesome 5 Free</code>, otherwise browser won't be able to interpret <code>content</code> correctly
and you'll be stuck with little squares.
Font-weight is not necessary, but it causes that solid look. If you let it out, you'll have an outlined icon.
Unicode that you put in <code>content</code> is dependent on the icon you chose, but it always starts with "\f".
You can copy the Unicode of the chosen icon here:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413039541/aezd_SU1B.png" alt="iconUnicode.PNG" /></p>
<blockquote>
<p>Don't forget the <code>\</code> at the start of your Unicode or it won't render correctly.</p>
</blockquote>
<p>Unlike in previous cases, here we have content, so <code>position: absolute</code> is not necessary, width and height will depend on the content.
However, we used <code>position: relative</code> and <code>left: -9px</code> to give the bullets a little breathing space.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413080891/T-VsNGaxd.png" alt="icons.PNG" /></p>
<h2 id="image-bullets">Image bullets</h2>
<p>In case you need your bullets to really look the part of your design, you might want to create them as images.</p>
<h3 id="html">HTML</h3>
<p><code>image.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"image.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"image-bullets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>If you want your bullets to look really stylish, you can even use images.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Those bullets are using image.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Isn't that yellow beautifull?<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/bullets-blog-code/-/blob/master/images/yellowBtn.png">Here</a> you can download the image I used, but you can use any image you want.
Image originates from <a target="_blank" href="https://www.wpclipart.com/">wpclipart</a></p>
<h3 id="image-as-a-content">Image as a content</h3>
<p>Inserting an image in a <code>::before</code> element is fairly simple:</p>
<ol>
<li>Inside your project, create a directory, where you're going to put your image and copy the image there (in my case <code>image/yellowBtn.png</code>).</li>
<li>Refer to your image in <code>content</code> with <code>parameter</code></li>
</ol>
<p>This is the whole code:</p>
<p><code>image.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.image-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-built_in">url</span>(images/yellowBtn.png);
}
</code></pre>
<p>Open your browser and check how it looks. Not good?
If you try to set height and width, like this:</p>
<p><code>image.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.image-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-built_in">url</span>(images/yellowBtn.png);
    <span class="hljs-attribute">height</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>it won't work. 
That's because you can't change the dimensions of the image when inserted this way.</p>
<p>You have two ways to solve that problem:</p>
<ol>
<li>Either you resize the image with a photo editor or online (unless you have a good reason, I suggest that option)</li>
<li>Use your image as a background (that's a solution to go with if, for example, you want those images to be of a different size depending on the device size)</li>
</ol>
<blockquote>
<p>You can do basic editing of your images with an online tool like <a target="_blank" href="https://picresize.com/">this one</a></p>
</blockquote>
<h3 id="image-as-a-background">Image as a background</h3>
<p>If you for some reason don't want to resize the image, you can set it as a background.</p>
<p>That case is fairly similar to the first one (square bullets).
We set an empty content, the position needs to be absolute and we have to specify width and height.
Because the position is <code>absolute</code>, we also need to set the position of a parent to <code>relative</code>.
We also need to set the background image. We can set it the same way we did before, with <code>url</code>.</p>
<p><code>image.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.image-bullets</span> &gt; <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.image-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(images/yellowBtn.png);
}
</code></pre>
<p>However, this still won't show our bullets. 
The magic property that is missing, is <code>background-size</code>.
We are going to set it to <code>contain</code>.</p>
<blockquote>
<p>Check all possible <code>background-size</code> values <a target="_blank" href="https://www.w3schools.com/cssref/css3_pr_background-size.asp">here</a>.</p>
</blockquote>
<p>Currently, bullets are covering part of our sentences, so we fix their position with <code>top</code> and <code>left</code>.</p>
<p>The whole code, that creates our image-bullets, now looks like this:</p>
<p><code>image.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.image-bullets</span> &gt; <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.image-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(images/yellowBtn.png);
    <span class="hljs-attribute">background-size</span>: contain;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">12px</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>And the result is this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413099690/wgt1w80zl.png" alt="images.PNG" /></p>
<h2 id="bullet-that-differs">Bullet that differs</h2>
<p>You can create a general look of your bullets and then change just a little part of one (or all) bullet.
You can do that with all the previous cases, not just with the icons as we are going to do now.
You could change any property, eg. color, position, shape, size...</p>
<h3 id="html">HTML</h3>
<p><code>different.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://kit.fontawesome.com/d465826c4f.js"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"different.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"different-bullets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>In case you need to pass some information with differents in bullets, you can do that too.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"important-icon"</span>&gt;</span>You can change the color to show the most important one.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"different-icon"</span>&gt;</span>You can change the shape to pass info about data you are showing..<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"bColor1"</span>&gt;</span>Or you can create a beautiful effect<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"bColor2"</span>&gt;</span>where each icon is styled<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"bColor3"</span>&gt;</span> just a little differently.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>First, we are going to create basic styling, that is the same for all the bullets.
CSS for that is almost the same as in icon.css, I only selected different icon and make it a little bigger.</p>
<p><code>different.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Font Awesome 5 Free"</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f669"</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">12px</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<h3 id="change-the-color">Change the color</h3>
<p>Maybe you want to emphasize one bullet with red color, so you show its importance.
This is how you make the bullet of <code>li</code> element with class <code>important-icon</code> red:</p>
<p><code>different.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-class">.important-icon</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff0000</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413378096/NcEWJl1o8.png" alt="different_red.PNG" /></p>
<h3 id="change-the-icon">Change the icon</h3>
<p>This is how you change the bullet icon of <code>li</code> element with class <code>different-icon</code>:</p>
<p><code>different.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-class">.different-icon</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f05a"</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413402783/QxxgWCAqa.png" alt="different_info.PNG" /></p>
<h3 id="style-each-icon-a-little-different">Style each icon a little different</h3>
<p>Sometimes you want each icon to be a little different,
but want to connect each <code>&lt;li&gt;</code> element to a certain color or create a linear-gradient effect.
Last three <code>&lt;li&gt;</code> elements of <code>&lt;ul class="different-bullets"&gt;</code> each have id. 
They all use the same icon, but we want to make each one different shade of pink:</p>
<p><code>different.css</code> </p>
<pre><code class="lang-css"> <span class="hljs-selector-id">#bColor1</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffb6c1</span>;
 }

 <span class="hljs-selector-id">#bColor2</span><span class="hljs-selector-pseudo">::before</span> {
     <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff69b4</span>;
 }

 <span class="hljs-selector-id">#bColor3</span><span class="hljs-selector-pseudo">::before</span> {
     <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff1493</span>;
 }
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413418723/2C_DiDPkI.png" alt="different_shades.PNG" /></p>
<p>All those different bullets look like this:</p>
<p><code>different.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">list-style</span>: none; <span class="hljs-comment">/* Remove default bullets */</span>
}

<span class="hljs-selector-tag">ul</span> &gt; <span class="hljs-selector-tag">li</span> {<span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>} <span class="hljs-comment">/* Stretching li elements a little so it looks prettier */</span>

<span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Font Awesome 5 Free"</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f669"</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">12px</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-class">.important-icon</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff0000</span>;
}

<span class="hljs-selector-class">.different-bullets</span> &gt; <span class="hljs-selector-tag">li</span><span class="hljs-selector-class">.different-icon</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f05a"</span>;
}

<span class="hljs-selector-id">#bColor1</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffb6c1</span>;
}

<span class="hljs-selector-id">#bColor2</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff69b4</span>;
}

<span class="hljs-selector-id">#bColor3</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff1493</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609413434553/3NCyaYnq9.png" alt="different.PNG" /></p>
<p>For example, I once connected a floorplan of some building with differently colored areas with a <code>ul</code> so each <code>li</code> had a square bullet colored corresponding with some part of a map.</p>
<h2 id="possible-mistakes">Possible mistakes</h2>
<p>If you're creating your custom bullets and they don't show up, those are the possible reasons:</p>
<ol>
<li>Maybe you forgot to set the color of the background (in the case of squares that don't have content)</li>
<li>You might either forgot to set position absolute or change the <code>display</code> to <code>block</code></li>
<li>Check if you turned off default bullets with <code>ul {list-style: none;}</code></li>
<li>In the case of using icons, did you write <code>\</code> before the Unicode of an icon, set the font-family, and import icons font?</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>In this tutorial, we looked over a few possibilities on how to style bullets, but options are almost limitless.
I hope that this tutorial helped you to learn to style beautiful bullets with different colors, images, and icons.</p>
<p>You can check the whole code <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/bullets-blog-code">here</a></p>
]]></content:encoded></item><item><title><![CDATA[HTML Canvas Christmas tutorial - part 3: MOVEMENT, BEZIER CURVE]]></title><description><![CDATA[Following part1 and part 2 of the tutorial you created a wonderful static Christmas card. But what's the point of having it on the computer, if nothing changes?
That's why we're going to add some simple movement on our card. Before that, we'll create...]]></description><link>https://girlthatlovestocode.com/html-canvas-christmas-tutorial-movement-bezier-curve</link><guid isPermaLink="true">https://girlthatlovestocode.com/html-canvas-christmas-tutorial-movement-bezier-curve</guid><category><![CDATA[HTML5]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[canvas]]></category><category><![CDATA[HTML Canvas]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Wed, 09 Dec 2020 13:22:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518696187/nHzYRWX2C.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Following <a target="_blank" href="https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-1-basics">part1</a> and <a target="_blank" href="https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-2-repetition-and-depth">part 2</a> of the tutorial you created a wonderful static Christmas card. But what's the point of having it on the computer, if nothing changes?
That's why we're going to add some simple movement on our card. Before that, we'll create a more complicated object, using Bezier Curve.</p>
<blockquote>
<p>You can see the code of the previous two tutorials <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/christmascanvas">here</a></p>
</blockquote>
<h2 id="what-will-you-create">What will you create?</h2>
<ol>
<li><p>Let's follow the star! We'll create more complex shapes, combining triangles and <a target="_blank" href="https://en.wikipedia.org/wiki/B%C3%A9zier_curve">Bezier curve</a> 
to create a comet.</p>
</li>
<li><p>More gifts! We'll create one more gift. That one will fall from the sky and land on the grass.</p>
</li>
<li><p>Santa's coming to town! We're going to include an image of Santa Claus that is going to ride through the air forever.</p>
</li>
</ol>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>basic knowledge of HTML</li>
<li>basic knowledge of JavaScript</li>
<li>basic understanding of HTML Canvas</li>
</ul>
<blockquote>
<p>We covered basics of HTML Canvas in the <a target="_blank" href="https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-1-basics">first part</a> of this tutorial</p>
</blockquote>
<h2 id="bigger-christmas-card">Bigger Christmas card</h2>
<p>We used all the available space on our canvas. Let's make it a little wider, so we can put more awesome things on it.</p>
<p>You need to make HTML Canvas in your <code>html</code> file wider. Switch the <code>width</code> you currently have with 800.</p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canpic"</span> <span class="hljs-attr">width</span> = <span class="hljs-string">800;</span> <span class="hljs-attr">height</span> = <span class="hljs-string">450;</span> &gt;</span>Your browser does not support the canvas element.<span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>
</code></pre>
<p>If you refresh the page, you can see that nothing (visible) happened. Your <code>canvas</code> element is bigger, but the image you drew, stayed the same.
Let's stretch the linear-gradient background we created in <em>part 1</em> over the whole canvas.</p>
<p>Find that part of the code:</p>
<p><code>JavaScript</code></p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> backgroundLinear = ctx.createLinearGradient(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">350</span>);
backgroundLinear.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">"#151c2e"</span>);
backgroundLinear.addColorStop(<span class="hljs-number">0.9</span>, <span class="hljs-string">"white"</span>);
backgroundLinear.addColorStop(<span class="hljs-number">1</span>,<span class="hljs-string">"green"</span>);
ctx.fillStyle = backgroundLinear;
ctx.fillRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">500</span>, <span class="hljs-number">450</span>);
</code></pre>
<p>and make the <code>fillRect</code> bigger, like this:</p>
<pre><code class="lang-js">ctx.fillRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">800</span>, <span class="hljs-number">450</span>);
</code></pre>
<p>That's the only number you have to change to make your background cover the whole canvas.</p>
<h2 id="comet">Comet</h2>
<p>This comet will consist of 2 separate parts:</p>
<ul>
<li>The star, drawn with 2 inverted equilateral triangles</li>
<li>Comet's tail, drawn with <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/bezierCurveTo">Bezier curve</a></li>
</ul>
<h3 id="follow-the-star">Follow the star</h3>
<blockquote>
<p>We're going to create a star using 2 triangles because it is mathematically less demanding. 
You could also draw it with the <code>lineTo</code> method, like in <a target="_blank" href="https://www.tutorialspoint.com/How-to-draw-a-star-by-using-canvas-HTML5">this example</a>.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518729195/FXgkALe_4.png" alt="comet.png" /></p>
<p>We are going to draw 2 overlapping yellow triangles (one facing down and one facing upward) with <code>lineTo</code>.</p>
<pre><code class="lang-js">ctx.fillStyle = <span class="hljs-string">"yellow"</span>;

<span class="hljs-comment">// triangle turned up</span>
ctx.beginPath();
ctx.moveTo(<span class="hljs-number">600</span>, <span class="hljs-number">145</span>);
ctx.lineTo(<span class="hljs-number">660</span>, <span class="hljs-number">50</span>);
ctx.lineTo(<span class="hljs-number">720</span>, <span class="hljs-number">145</span>);
ctx.closePath();
ctx.fill();

<span class="hljs-comment">// triangle turned down</span>
ctx.beginPath();
ctx.moveTo(<span class="hljs-number">600</span>, <span class="hljs-number">85</span>);
ctx.lineTo(<span class="hljs-number">720</span>, <span class="hljs-number">85</span>);
ctx.lineTo(<span class="hljs-number">660</span>, <span class="hljs-number">180</span>);
ctx.closePath();
ctx.fill();
</code></pre>
<p>As you can see, here we didn't do anything else than we did in the previous tutorial. 
We selected <code>fillStyle</code> color and we begun path (<code>ctx.beginPath()</code>) in the middle of the canvas (<code>moveTo(x, y)</code>)
After that, we draw lines to 2 more points (<code>lineTo(x, y)</code>) and finally we closed the path back to where it began (<code>ctx.closePath()</code>) and filled it with the selected color (<code>ctx.fill()</code>).
You can see all the important points on the graph.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518754085/DjYoq-qQb.png" alt="juststar.PNG" /></p>
<h4 id="bezier-curve">Bézier curve</h4>
<p>A Bézier curve is a curve used in computer graphics and related fields.
On canvas, it's defined with 4 points - a beginning (that is not defined in the function), an ending, and 2 control points that usually aren't located on the curve. 
You could imagine it as a loose string that is fixed at both ends. You're holding it somewhere in the middle with both hands and you move those hands.
With movements of your hand, you're creating different curved shapes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518778748/KpBFdx6e2.png" alt="bezierexplanation.png" /></p>
<p>We create a Bézier curve with <code>bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)</code> method that accepts 3 x 2 parameters.</p>
<ul>
<li><strong>x</strong> of <strong>first control</strong> point</li>
<li><strong>y</strong> of <strong>first control</strong> point</li>
<li><strong>x</strong> of <strong>second control</strong> point</li>
<li><strong>y</strong> of <strong>second control</strong> point</li>
<li><strong>x</strong> of <strong>end</strong> point</li>
<li><strong>y</strong> of <strong>end</strong> point</li>
</ul>
<p>As you saw before Bézier should be defined with 4 points - the beginning point is missing in the method. 
The method as a beginning point uses the latest point in the current path. That latest point can be changed with the <code>moveTo()</code> method.</p>
<p>We are going to draw 2 similar Bézier curves, one under the other. At the right, they will be connected with a straight, vertical line.
At the left, they'll be connected with a line, broken somewhere in the middle.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518816100/7zZrD-3aN.png" alt="cometTail.png" /></p>
<pre><code class="lang-js">ctx.beginPath();
ctx.moveTo(<span class="hljs-number">500</span>,<span class="hljs-number">80</span>);

<span class="hljs-comment">// first bezierCurve (top edge of comet's tail)</span>
ctx.bezierCurveTo(<span class="hljs-number">550</span>, <span class="hljs-number">30</span>, <span class="hljs-number">600</span>, <span class="hljs-number">30</span>, <span class="hljs-number">650</span>, <span class="hljs-number">80</span>);

<span class="hljs-comment">// straight line from first bezier curve to the second one on the right side (in the star)</span>
ctx.lineTo(<span class="hljs-number">650</span>,<span class="hljs-number">130</span>);

<span class="hljs-comment">// second bezierCurve (bottom edge of comet's tail)</span>
ctx.bezierCurveTo(<span class="hljs-number">600</span>, <span class="hljs-number">80</span>, <span class="hljs-number">550</span>, <span class="hljs-number">80</span>, <span class="hljs-number">500</span>, <span class="hljs-number">130</span>);

<span class="hljs-comment">// pointy part of the tail</span>
ctx.lineTo(<span class="hljs-number">520</span>, <span class="hljs-number">90</span>);

ctx.closePath();
ctx.fill();
</code></pre>
<p>Using the points specified on the graph, we moved our <code>brush</code> to the starting point of the comet's tail and drew the first Bézier curve with <code>bezierCurveTo</code>.
With <code>lineTo</code> we moved a little lower and draw the second Bézier curve - this one from right to left as our 'brush' was on the right side of the canvas.
With <code>lineTo</code> we created a little indentation at the end of the tail and with <code>closePath</code> closed the shape.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518885974/C9J7wN5MJ.png" alt="drawnComet.PNG" /></p>
<blockquote>
<p>I created two small red circles with the same coordinates as the two checkpoints, so you can check for yourself that checkpoints are indeed not on the tail:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518842897/jAWE4rJZ9.png" alt="beziercheckpoints.PNG" /></p>
</blockquote>
<h2 id="object-movement-on-canvas">Object movement on <code>canvas</code></h2>
<p>Since HTML canvas works like a real-world canvas, you can't really move an object.
You can erase said object on the previous location and draw it again on the new one. 
You can imagine object movement on <code>canvas</code> as a movement of a picture in a <a target="_blank" href="https://www.youtube.com/watch?v=ntD2qiGx-DY">flipbook</a>.</p>
<p>But when you move an object, you create a problem.
Pixels of a drawn object replace everything that was there before.
That means that once you create an object over the background, things that created the background disappear.
If you then move that object, on the place that it was before, remains only an empty canvas. 
HTML Canvas has no memory of what was there before, so it can't put the background back once the object moves.</p>
<p>That is solvable in three ways:</p>
<ol>
<li>You can recreate the missing part of the canvas</li>
<li>You can recreate the whole canvas content every time an object moves</li>
<li>You can create more than one canvas and on one put the background content and moving objects on the other</li>
</ol>
<p>Recreating the missing part is complicated, especially when said background changes rapidly throughout the picture. That's useful only if you have a very big canvas and the background is simple.
If there's not a lot going on on the canvas (eg. just gradient in the background) and the canvas isn't very big, it might be a good idea to recreate the whole canvas each time the object moves.</p>
<p>Because we created a lot of content on our canvas, we're going to use the third option - we'll create another, overlapping canvas.</p>
<p>Put another <code>canvas</code> in your <code>html</code> like this:</p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canpic"</span> <span class="hljs-attr">width</span> = <span class="hljs-string">800;</span> <span class="hljs-attr">height</span> = <span class="hljs-string">450;</span> &gt;</span>Your browser does not support the canvas element.<span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canmovement"</span> <span class="hljs-attr">width</span> = <span class="hljs-string">800;</span> <span class="hljs-attr">height</span> = <span class="hljs-string">450;</span> &gt;</span>Your browser does not support the canvas element.<span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>
</code></pre>
<p>This new <code>canvas</code> has to have the same width and height as the first one and a unique <code>id</code>.
By default, those two canvases will be put next to each other, so you need to change their position to absolute and put them on each other.
Because that's the only <code>CSS</code> we'll need, we'll put it in the<code>&lt;head&gt;</code> of the HTML file.</p>
<p><code>HTML</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Awesome canvas<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-id">#canpic</span>, <span class="hljs-selector-id">#canmovement</span> {
            <span class="hljs-attribute">position</span>: absolute;
            <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<h2 id="gift-falling-from-the-sky">Gift falling from the sky!</h2>
<p>We'll create a gift, similar to those we created in the part 2 that will move straight down. 
That means, only the <code>y</code> value will change, <code>x</code> will stay the same.
Since we'll draw the <em>falling gift</em> on the new canvas we created, we'll also need to create a new 'brush' (context) for it.</p>
<p>After creating a 'brush', we'll create a function <code>draw</code>, that will draw a (for now) non-moving gift.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> canvas_moving = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canmovement"</span>);
<span class="hljs-keyword">const</span> ctx_mov = canvas_moving.getContext(<span class="hljs-string">"2d"</span>);

<span class="hljs-keyword">var</span> gift_x = <span class="hljs-number">550</span>,
    gift_y = <span class="hljs-number">200</span>,
    gift_height = <span class="hljs-number">100</span>,
    gift_width = <span class="hljs-number">150</span>,
    mov_ribbon_width = <span class="hljs-number">10</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{

    ctx_mov.fillStyle = <span class="hljs-string">'red'</span>
    ctx_mov.fillRect(gift_x, gift_y, gift_width, gift_height)
    ctx_mov.strokeRect(gift_x, gift_y, gift_width, gift_height)

    ctx_mov.fillStyle = <span class="hljs-string">'blue'</span>

    <span class="hljs-comment">//vertical ribbon</span>
    ctx_mov.fillRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);
    ctx_mov.strokeRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);

    <span class="hljs-comment">//horizontal ribbon</span>
    ctx_mov.fillRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);
    ctx_mov.strokeRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);
}
</code></pre>
<p>At the top, we created a new context for the second <code>canvas</code>. 
Outside the <code>draw</code> function, we set the variables that determine the size and the position of the gift.
The current <code>draw</code> function should look completely familiar. 
It creates a big red square with a blue ribbon on it the same way the code in the <code>for loop</code> created other gifts.</p>
<p>We need to add the function that will provide the movement.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">movement</span>(<span class="hljs-params"></span>) </span>{
    requestAnimationFrame(movement);

    gift_y += <span class="hljs-number">2</span>;

    draw();
}

movement()
</code></pre>
<p>Function <code>movement</code> has 3 parts:</p>
<ol>
<li><p><code>requestAnimationFrame()</code>
 requestAnimationFrame() is a better alternative to setInterval(), but its effects are similar.
 The method takes a callback as an argument and invokes it before the repaint, though updating an animation.</p>
<blockquote>
<p><a target="_blank" href="https://css-tricks.com/using-requestanimationframe/">Read more</a></p>
</blockquote>
</li>
<li><p><code>gift_y += 2;</code>
 Each time the callback function invokes, our gift will be 2px lower.</p>
</li>
<li><p><code>draw()</code>
 Call to a function that draws our gift each time the <code>movement</code> function is invoked. </p>
</li>
</ol>
<p>Don't forget to execute the function!</p>
<p>The effect we get is uncanny and definitely not what we had in mind.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518949641/MRxLk4Wmj.png" alt="giftdrag.PNG" /></p>
<p>We are repainting the gift over and over again, but we are not deleting the previous one. Add the black stroke around it and you get that weird dark red thing with a blue stripe in the middle ruining our beautiful canvas!
And so we come to a reason why we create the second canvas. 
Each time, before drawing on it, we'll clear the whole canvas. We add that code at the beginning of the <code>draw()</code> function.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{

    ctx_mov.clearRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas_moving.width, canvas_moving.height)

    ctx_mov.fillStyle = <span class="hljs-string">'red'</span>
    ctx_mov.fillRect(gift_x, gift_y, gift_width, gift_height)
    ctx_mov.strokeRect(gift_x, gift_y, gift_width, gift_height)

    ctx_mov.fillStyle = <span class="hljs-string">'blue'</span>

    <span class="hljs-comment">//vertical ribbon</span>
    ctx_mov.fillRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);
    ctx_mov.strokeRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);

    <span class="hljs-comment">//horizontal ribbon</span>
    ctx_mov.fillRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);
    ctx_mov.strokeRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);
}
</code></pre>
<p>As you can see, the method <code>clearRect()</code> is the exact opposite of the <code>fillRect</code>. Its parameters are the same:</p>
<ul>
<li><em>x</em> coordinate of the left corner of the square</li>
<li><em>y</em> coordinate of the left corner of the square</li>
<li><em>width</em> of the square</li>
<li><em>height</em> of the square</li>
</ul>
<p>The only difference is, <code>fillRect()</code> creates a rectangle, and <code>clearRect()</code> deletes everything in the specified rectangle.
That's how we create movement on canvas -&gt; we redraw the gift with different <code>y</code> coordinate, each time the <code>draw()</code> function is invoked, but before that, we delete either everything or just part of what we draw before.</p>
<blockquote>
<p>You don't necessarily need to clear the whole canvas to create the movement. You also could each time just call clearRect() with the same parameters as you used to previously create the gift, thus deleting only the part of the canvas where the gift had previously been.
That might be useful if you'd create the tree on the same canvas as the gift and would want for the tree to stay the same and only delete the gift.</p>
</blockquote>
<p>But that didn't fix all of our problems. The gift is now moving and doesn't live an elephant's trail behind it, but it starts in the middle of the screen and then disappears off it.
Let's change that.</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> gift_x = <span class="hljs-number">550</span>,
    gift_y = <span class="hljs-number">-200</span>,
    gift_height = <span class="hljs-number">100</span>,
    gift_width = <span class="hljs-number">150</span>,
    mov_ribbon_width = <span class="hljs-number">10</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    ...
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">movement</span>(<span class="hljs-params"></span>) </span>{
    requestAnimationFrame(movement);

    <span class="hljs-comment">// gift must stop when its bottom is on the same height as the tree (360 - gift_height)</span>
    <span class="hljs-keyword">if</span>(gift_y &lt; (<span class="hljs-number">360</span> - gift_height)) {
        gift_y += <span class="hljs-number">2</span>;
    }

    draw();
}

movement()
</code></pre>
<p>As you can see, that was easy enough. We only changed 2 small parts of the code:</p>
<ol>
<li>Our variable <code>gift_y</code> is now set to <em>-200</em> and that sets the start of our gift off the canvas.</li>
<li>The step change of <code>gift_y</code> is now wrapped in an <em>if</em>. When incremented <em>y</em> reaches a certain value, it stops incrementing. And though the gift stops moving.</li>
</ol>
<p>Refresh the page and you'll see the gift behave exactly how we wanted.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607518972324/fUBrkp8tg.png" alt="falling_gift.PNG" /></p>
<h2 id="santa-on-his-sleigh">Santa on his sleigh</h2>
<p>When you created the falling gift, you learned the basics about movement on the canvas. 
Now we are going to create a little more complicated, repetitive movement and learn how to use an image in canvas along the way.</p>
<p>Before you can put ("draw") an image on the canvas you need first to create the image and wait for it to load. 
You can do that by using the onload property of the image object.</p>
<p>The Image() constructor creates a new HTMLImageElement instance. It is functionally equivalent to document.createElement('img') (https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image)</p>
<blockquote>
<p><a target="_blank" href="https://www.nashvail.me/blog/canvas-image">Here</a> is a very detailed explanation of how the image loading on canvas works.</p>
</blockquote>
<p>You can get that image at http://www.pngall.com/sleigh-png/download/29075, name it santa_image.png, and put it in the same folder as your HTML and Javascript file.</p>
<pre><code class="lang-js">santa_img = <span class="hljs-keyword">new</span> Image();
santa_img.src = <span class="hljs-string">"./santa_image.png"</span>
santa_img.onload = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ctx_mov.drawImage(santa_img, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>)};
</code></pre>
<p><strong>This doesn't work, does it?</strong></p>
<p>Well, actually, it does.
We put that image on the canvas with id 'canmovement'. That's the same canvas we created the falling gift on.
And that canvas clears itself on repeat before the gift is drawn on it again. But the image is outside the function that covers that.
So it <strong>is created</strong> in the start, but the canvas clears itself before we can see it.
Let's comment out the falling gift part for a little while. But leave the context creation!</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> canvas_moving = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canmovement"</span>);
<span class="hljs-keyword">const</span> ctx_mov = canvas_moving.getContext(<span class="hljs-string">"2d"</span>);

<span class="hljs-comment">/*
var gift_x = 550,

...

movement()
*/</span>

santa_img = <span class="hljs-keyword">new</span> Image();
santa_img.src = <span class="hljs-string">"./santa_image.png"</span>
santa_img.onload = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ctx_mov.drawImage(santa_img, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>)};
</code></pre>
<p>You can see that now by some miracle of commenting god, it works!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607519006014/_XuWwiRHv.png" alt="santanotmoving.PNG" /></p>
<p>But that's not what we wanted, we need to move the <code>santa_img</code> part inside the <code>draw</code> function.
But we can't simply move all of the code inside. We can't call the <code>.onload()</code> each time the canvas refreshes.
We need first to load the image and then execute everything else.</p>
<p>Outside the function, we need to create a new Image and assign its source. 
Then we call the movement function when the image loads. </p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> santa_img = <span class="hljs-keyword">new</span> Image(),
santa_img.onload = movement;
santa_img.src = <span class="hljs-string">"./santa_image.png"</span>
</code></pre>
<p>The only thing missing now is moving the drawImage method to the bottom of the <code>draw</code> function.</p>
<p>Whole code now looks like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> canvas_moving = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canmovement"</span>);
<span class="hljs-keyword">const</span> ctx_mov = canvas_moving.getContext(<span class="hljs-string">"2d"</span>);

<span class="hljs-keyword">var</span> gift_x = <span class="hljs-number">550</span>,
    gift_y = <span class="hljs-number">-200</span>,
    gift_height = <span class="hljs-number">100</span>,
    gift_width = <span class="hljs-number">150</span>,
    mov_ribbon_width = <span class="hljs-number">10</span>,
    santa_img = <span class="hljs-keyword">new</span> Image();

santa_img.src = <span class="hljs-string">"./santa_image.png"</span>
santa_img.onload = movement;


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{

    ctx_mov.clearRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas_moving.width, canvas_moving.height)

    ctx_mov.fillStyle = <span class="hljs-string">'red'</span>
    ctx_mov.fillRect(gift_x, gift_y, gift_width, gift_height)
    ctx_mov.strokeRect(gift_x, gift_y, gift_width, gift_height)

    ctx_mov.fillStyle = <span class="hljs-string">'blue'</span>

    <span class="hljs-comment">//vertical ribbon</span>
    ctx_mov.fillRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);
    ctx_mov.strokeRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);

    <span class="hljs-comment">//horizontal ribbon</span>
    ctx_mov.fillRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);
    ctx_mov.strokeRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);

    ctx_mov.drawImage(santa_img, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">movement</span>(<span class="hljs-params"></span>) </span>{
    requestAnimationFrame(movement);

    <span class="hljs-comment">// gift must sto when bottom is on the same height as the tree (360 - gift_height)</span>
    <span class="hljs-keyword">if</span>(gift_y &lt; (<span class="hljs-number">360</span> - gift_height)) {
        gift_y += <span class="hljs-number">2</span>;
    }

    draw();
}
</code></pre>
<p>Now both, the moving gift and the Santa are showing, but Santa's not moving yet.
We need to add some kind of change to Santa's coordinates.
Switch the <strong>x</strong> and <strong>y</strong> coordinates inside the <code>drawImage</code> method that are currently numbers for new variables, <code>santa_x</code> and <code>santa_y</code>.</p>
<pre><code class="lang-js">    ctx_mov.drawImage(santa_img, santa_x, santa_y);
</code></pre>
<p>And don't forget to define them on the top, where all our variables are defined.</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> gift_x = <span class="hljs-number">550</span>,
    gift_y = <span class="hljs-number">-200</span>,
    gift_height = <span class="hljs-number">100</span>,
    gift_width = <span class="hljs-number">150</span>,
    fall_ribbon_width = <span class="hljs-number">10</span>,
    santa_img = <span class="hljs-keyword">new</span> Image(),
    santa_x = <span class="hljs-number">10</span>,
    santa_y = <span class="hljs-number">10</span>;
</code></pre>
<p>Now, let's discuss what we are trying to achieve. I want the sleigh to start off the screen and slowly rising toward the right side.
When the sleigh completely disappears from the screen, I want them to start rasing from the starting point and so on repeat.
We need to change the starting <code>santa_x</code> and <code>santa_y</code> to off the screen and then increment both inside the movement.
The sleigh will disappear from the canvas when <code>santa_x</code> is bigger than the canvas width.
When that happens, we need to reset both values back to the starting ones.</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> gift_x = <span class="hljs-number">550</span>,
    gift_y = <span class="hljs-number">-200</span>,
    gift_height = <span class="hljs-number">100</span>,
    gift_width = <span class="hljs-number">150</span>,
    mov_ribbon_width = <span class="hljs-number">10</span>,
    santa_img = <span class="hljs-keyword">new</span> Image(),
    santa_x = <span class="hljs-number">-300</span>,
    santa_y = canvas.height;

santa_img.src = <span class="hljs-string">"./santa_image.png"</span>
santa_img.onload = movement;


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{

    ... Gift drawing ...

    ctx_mov.drawImage(santa_img, santa_x, santa_y);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">movement</span>(<span class="hljs-params"></span>) </span>{
    requestAnimationFrame(movement);

    <span class="hljs-comment">// gift must sto when bottom is on the same height as the tree (360 - gift_height)</span>
    <span class="hljs-keyword">if</span>(gift_y &lt; (<span class="hljs-number">360</span> - gift_height)) {
        gift_y += <span class="hljs-number">2</span>;
    }

    <span class="hljs-keyword">if</span>(santa_x &gt; canvas.width) {
        santa_x = <span class="hljs-number">-300</span>
        santa_y = canvas.height
    } <span class="hljs-keyword">else</span> {
        santa_x += <span class="hljs-number">2</span>;
        santa_y -= <span class="hljs-number">1</span>;
    }

    draw();
}
</code></pre>
<p>As you can see, we changed <code>santa_y</code>to <code>canvas.height</code> - that means that the Santa image is just under the canvas.
Inside the ´movement´ function we have an if clause that checks if <code>santa_x</code> is bigger than canvases width.
If it is, the images reset to the starting position.
If not, Santa is moving to the right a little more than it raises to the top.</p>
<p>Here's the whole code that covers movement: </p>
<pre><code class="lang-js">
<span class="hljs-keyword">const</span> canvas_moving = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canmovement"</span>);
<span class="hljs-keyword">const</span> ctx_mov = canvas_moving.getContext(<span class="hljs-string">"2d"</span>);

<span class="hljs-keyword">var</span> gift_x = <span class="hljs-number">550</span>,
    gift_y = <span class="hljs-number">-200</span>,
    gift_height = <span class="hljs-number">100</span>,
    gift_width = <span class="hljs-number">150</span>,
    mov_ribbon_width = <span class="hljs-number">10</span>,
    santa_img = <span class="hljs-keyword">new</span> Image(),
    santa_x = <span class="hljs-number">-300</span>,
    santa_y = canvas.height;

santa_img.src = <span class="hljs-string">"./santa_image.png"</span>
santa_img.onload = movement;


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{

    ctx_mov.clearRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas_moving.width, canvas_moving.height)

    ctx_mov.fillStyle = <span class="hljs-string">'red'</span>
    ctx_mov.fillRect(gift_x, gift_y, gift_width, gift_height)
    ctx_mov.strokeRect(gift_x, gift_y, gift_width, gift_height)

    ctx_mov.fillStyle = <span class="hljs-string">'blue'</span>

    <span class="hljs-comment">//vertical ribbon</span>
    ctx_mov.fillRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);
    ctx_mov.strokeRect(gift_x + gift_width/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span> , gift_y, mov_ribbon_width, gift_height);

    <span class="hljs-comment">//horizontal ribbon</span>
    ctx_mov.fillRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);
    ctx_mov.strokeRect(gift_x, gift_y + gift_height/<span class="hljs-number">2</span> - mov_ribbon_width/<span class="hljs-number">2</span>, gift_width, mov_ribbon_width);

    ctx_mov.drawImage(santa_img, santa_x, santa_y);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">movement</span>(<span class="hljs-params"></span>) </span>{
    requestAnimationFrame(movement);

    <span class="hljs-comment">// gift must sto when bottom is on the same height as the tree (360 - gift_height)</span>
    <span class="hljs-keyword">if</span>(gift_y &lt; (<span class="hljs-number">360</span> - gift_height)) {
        gift_y += <span class="hljs-number">2</span>;
    }

    <span class="hljs-keyword">if</span>(santa_x &gt; canvas.width) {
        santa_x = <span class="hljs-number">-300</span>
        santa_y = canvas.height
    } <span class="hljs-keyword">else</span> {
        santa_x += <span class="hljs-number">2</span>;
        santa_y -= <span class="hljs-number">1</span>;
    }

    draw();
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607519025269/1A2WoqFMb.png" alt="finnished.PNG" /></p>
<p>And that's it!</p>
<p>Congratulations, you came to the end of the Christmas Canvas tutorial!</p>
<blockquote>
<p><a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/christmascanvas">Check the code from all the parts of the tutorial</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[HTML Canvas Christmas tutorial - part 2: REPETITION and DEPTH]]></title><description><![CDATA[You learned a lot in the previous tutorial, but let's be honest, the Christmas tree needs presents underneath. So let's add them and improve our knowledge.
What will you do?

What's Christmas without presents!? We are going to add a stack of them nex...]]></description><link>https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-2-repetition-and-depth</link><guid isPermaLink="true">https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-2-repetition-and-depth</guid><category><![CDATA[ #2Articles1Week]]></category><category><![CDATA[HTML Canvas]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[canvas]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Tue, 01 Dec 2020 13:45:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606830115784/B0AU9nG2n.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You learned a lot in the <a target="_blank" href="https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-1-basics">previous tutorial</a>, but let's be honest, the Christmas tree needs presents underneath. So let's add them and improve our knowledge.</p>
<h2 id="what-will-you-do">What will you do?</h2>
<ol>
<li><p>What's Christmas without presents!? We are going to add a stack of them next to the tree. 
Each next one is going to be smaller and they're gonna be different colors with ribbons of different colors.</p>
</li>
<li><p>We'll make the trunk more 3D by creating a simple linear-gradient effect - it will be darker on both sides and lighter in the middle.</p>
</li>
<li><p>On the tree crown, we'll create a little texture by exchanging lighter and darker green.</p>
</li>
<li><p>We are also going to create 3D baubles with a radial gradient.</p>
</li>
</ol>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>basic knowledge of HTML</li>
<li>basic knowledge of JavaScript</li>
<li>basic knowledge of HTML Canvas</li>
</ul>
<blockquote>
<p>We covered the basics of HTML Canvas in the <a target="_blank" href="https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-1-basics">previous tutorial</a></p>
</blockquote>
<h2 id="presents">Presents</h2>
<p>We're going to draw 5 presents. Each of them will be built from <strong>3 rectangles</strong>. The first one will be square for the <em>box</em>. Two thin and long will build the <em>ribbon</em> (one vertical and one horizontal). They will be stacked one on top of another. The bottom one will be largest while others will be gradually smaller. So let's get to work.</p>
<h3 id="boxes">Boxes</h3>
<p>Drawing of each present starts at its top left corner. You can see the coordinates of their top-left corners in the image below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829341657/P2NKgajiC.png" alt="gifts.png" /></p>
<p>First, to the bottom of <em>canvas.js</em> add values for the gift:</p>
<pre><code class="lang-js"><span class="hljs-comment">// code from the previous tutorial is above that comment</span>

<span class="hljs-keyword">var</span> height_gift = <span class="hljs-number">100</span>
<span class="hljs-keyword">var</span> width_gift = height_gift <span class="hljs-comment">// you want square</span>
<span class="hljs-keyword">var</span> x_gift = <span class="hljs-number">300</span>
<span class="hljs-keyword">var</span> y_gift = <span class="hljs-number">260</span>
</code></pre>
<p>As you can see in the image, the top left corner of the first gift is positioned at <em>x=300</em> and <em>y=260</em>. Its height and width are 100px. Next, you need to draw this box to the canvas.</p>
<pre><code class="lang-js"><span class="hljs-comment">// code from the previous tutorial is above that comment</span>

<span class="hljs-keyword">var</span> height_gift = <span class="hljs-number">100</span>
<span class="hljs-keyword">var</span> width_gift = height_gift <span class="hljs-comment">// you want square</span>
<span class="hljs-keyword">var</span> x_gift = <span class="hljs-number">300</span>
<span class="hljs-keyword">var</span> y_gift = <span class="hljs-number">260</span>

ctx.strokeStyle = <span class="hljs-string">"black"</span>;
ctx.fillStyle = <span class="hljs-string">"red"</span>;

ctx.fillRect(x_gift, y_gift, width_gift, height_gift);
ctx.strokeRect(x_gift, y_gift, width_gift, height_gift);
</code></pre>
<p>It's filled with red color by using <code>fillRect</code> and outlined with black line by using <code>strokeRect</code>. Open <em>canvas.html</em> in your browser to see the red square next to the Christmas tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829396127/wyl_776er.png" alt="christmas1.png" /></p>
<p>The first one is there but we need to create 4 more. Replace code you've just added with this <em>for</em> loop:</p>
<pre><code class="lang-js"><span class="hljs-comment">// code from the previous tutorial is above that comment</span>

<span class="hljs-keyword">var</span> height_gift = <span class="hljs-number">100</span>
<span class="hljs-keyword">var</span> width_gift = height_gift <span class="hljs-comment">// you want square</span>
<span class="hljs-keyword">var</span> x_gift = <span class="hljs-number">300</span>
<span class="hljs-keyword">var</span> y_gift = <span class="hljs-number">260</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j = <span class="hljs-number">0</span>; j &lt; <span class="hljs-number">5</span>; j++) {

   ctx.strokeStyle = <span class="hljs-string">"black"</span>;
   ctx.fillStyle = <span class="hljs-string">"red"</span>;

   ctx.fillRect(x_gift, y_gift, width_gift, height_gift);
   ctx.strokeRect(x_gift, y_gift, width_gift, height_gift);

   height_gift = ((<span class="hljs-number">4</span> - j) * <span class="hljs-number">20</span>)
   width_gift = height_gift
   x_gift = x_gift + <span class="hljs-number">10</span>
   y_gift = y_gift - height_gift

}
</code></pre>
<p>As we can see from the diagram, each next gift will be 20px lower <code>height_gift = ((4 - j) * 20)</code> and 20px narrower <code>width_gift = height_gift</code>. If we want a nice pyramid-shaped structure, we need to move each next gift half of that 20px to the right <code>x_gift = x_gift + 10</code>.
While we start drawing each gift in the bottom left corner we need to start the next gift exactly its height higher than we started the last gift <code>y_gift = y_gift - height_gift</code> (to go higher you need to lower the <code>y</code>). We don't want to alter the numbers for the first gift, so we'll change our values at the end of our <em>for</em> loop to set them for the next gift.</p>
<p>Refresh your browser. You should see 5 red boxes stacked one on another.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829484484/HUNlLaTIm.png" alt="basicWithBoxes.PNG" /></p>
<h3 id="ribbon">Ribbon</h3>
<p>Now we only have 5 red boxes, stacked on one another. If we want them to look like gifts, we need to put a ribbon on them. We'll keep it simple and add vertical and horizontal blue stripes to it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829510760/ic-iIj4wz.png" alt="singleGift.png" /></p>
<p>Add code that will draw the ribbon, like this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// code from the previous tutorial is above that comment</span>

<span class="hljs-keyword">var</span> height_gift = <span class="hljs-number">100</span>
<span class="hljs-keyword">var</span> width_gift = height_gift <span class="hljs-comment">// you want square</span>
<span class="hljs-keyword">var</span> x_gift = <span class="hljs-number">300</span>
<span class="hljs-keyword">var</span> y_gift = <span class="hljs-number">260</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j = <span class="hljs-number">0</span>; j &lt; <span class="hljs-number">5</span>; j++) {

   ctx.strokeStyle = <span class="hljs-string">"black"</span>;
   ctx.fillStyle = <span class="hljs-string">"red"</span>;

   ctx.fillRect(x_gift, y_gift, width_gift, height_gift);
   ctx.strokeRect(x_gift, y_gift, width_gift, height_gift);

   ctx.fillStyle = <span class="hljs-string">"blue"</span>;

   <span class="hljs-keyword">var</span> ribbon_width = <span class="hljs-number">10</span> - j;

   <span class="hljs-comment">// vertical ribbon</span>
   ctx.fillRect(x_gift + width_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span> , y_gift, ribbon_width, height_gift);
   ctx.strokeRect(x_gift + width_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span> , y_gift, ribbon_width, height_gift);

   <span class="hljs-comment">// horizontal ribbon</span>
   ctx.fillRect(x_gift, y_gift + height_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span>, width_gift, ribbon_width);
   ctx.strokeRect(x_gift, y_gift + height_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span>, width_gift, ribbon_width);

   height_gift = ((<span class="hljs-number">4</span> - j) * <span class="hljs-number">20</span>)
   width_gift = height_gift
   x_gift = x_gift + <span class="hljs-number">10</span>
   y_gift = y_gift - height_gift

}
</code></pre>
<p>The smaller the gift, the narrower will be the ribbon. The middle of the ribbon will align with the middle of the gift.
But, because we start drawing a rectangle at its top left, we need to move half the width of the ribbon higher (on the horizontal ribbon) <code>y_gift + height_gift/2 - ribbon_width/2</code> or half the ribbon width to the left (on the vertical ribbon) <code>x_gift + width_gift/2 - ribbon_width/2</code>. As with the boxes, we stroke a black line around the ribbons.</p>
<p>Refresh the browser to see 5 gifts with ribbons:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829576268/ZUWp48YeL.png" alt="christmas2.png" /></p>
<h3 id="colorful-presents">Colorful presents</h3>
<p>Let's make presents colorful to make them a little more appealing. We can do that by assigning each box and each ribbon color randomly. At the bottom of the <em>canvas.js</em> add functions to generate random color for presents:</p>
<pre><code class="lang-js">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">randomInteger</span>(<span class="hljs-params">max, min</span>) </span>{
   <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random()*(max-min)) + min;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">randomColor</span>(<span class="hljs-params"></span>)</span>{
   <span class="hljs-keyword">return</span> <span class="hljs-string">'rgb('</span> + randomInteger(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>) + <span class="hljs-string">','</span> + randomInteger(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>) + <span class="hljs-string">','</span> + randomInteger(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>) +<span class="hljs-string">')'</span>;
}
</code></pre>
<p>The first function that returns a random integer between a given minimum and maximum number. The second one returns color in RGB format. It uses <code>randomInteger</code> function to generate a number between 0 and 255 to create R, G, and B parts of the RGB.</p>
<p>Assign the return of the <code>randomColor</code> function to <em>fillStyle</em> <code>ctx.fillStyle = randomColor();</code> of both, boxes and ribbons.</p>
<pre><code class="lang-js"><span class="hljs-comment">// code from previous tutorial is above that comment</span>

<span class="hljs-keyword">var</span> height_gift = <span class="hljs-number">100</span>
<span class="hljs-keyword">var</span> width_gift = height_gift <span class="hljs-comment">// you want square</span>
<span class="hljs-keyword">var</span> x_gift = <span class="hljs-number">300</span>
<span class="hljs-keyword">var</span> y_gift = <span class="hljs-number">260</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j = <span class="hljs-number">0</span>; j &lt; <span class="hljs-number">5</span>; j++) {

   ctx.strokeStyle = <span class="hljs-string">"black"</span>;
   ctx.fillStyle = randomColor();

   ctx.fillRect(x_gift, y_gift, width_gift, height_gift);
   ctx.strokeRect(x_gift, y_gift, width_gift, height_gift);

   ctx.fillStyle = randomColor();

   <span class="hljs-keyword">var</span> ribbon_width = <span class="hljs-number">10</span> - j;

   <span class="hljs-comment">// vertical ribbon</span>
   ctx.fillRect(x_gift + width_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span> , y_gift, ribbon_width, height_gift);
   ctx.strokeRect(x_gift + width_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span> , y_gift, ribbon_width, height_gift);

   <span class="hljs-comment">// horizontal ribbon</span>
   ctx.fillRect(x_gift, y_gift + height_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span>, width_gift, ribbon_width);
   ctx.strokeRect(x_gift, y_gift + height_gift/<span class="hljs-number">2</span> - ribbon_width/<span class="hljs-number">2</span>, width_gift, ribbon_width);


   height_gift = ((<span class="hljs-number">4</span> - j) * <span class="hljs-number">20</span>)
   width_gift = height_gift
   x_gift = x_gift + <span class="hljs-number">10</span>
   y_gift = y_gift - height_gift

}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">randomInteger</span>(<span class="hljs-params">max, min</span>) </span>{
   <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random()*(max-min)) + min;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">randomColor</span>(<span class="hljs-params"></span>)</span>{
   <span class="hljs-keyword">return</span> <span class="hljs-string">'rgb('</span> + randomInteger(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>) + <span class="hljs-string">','</span> + randomInteger(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>) + <span class="hljs-string">','</span> + randomInteger(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>) +<span class="hljs-string">')'</span>;
}
</code></pre>
<p>Refresh your browser again and you should see colorful gifts and ribbons. They will change after every refresh:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829660545/-CxpUBCPR.png" alt="christmas3.png" /></p>
<h2 id="3d-trunk">3D Trunk</h2>
<p>In previous tutorial we drew brown trunk by setting solid color and filling rectangle with it:</p>
<pre><code class="lang-js">ctx.fillStyle = <span class="hljs-string">"brown"</span>;
ctx.fillRect(<span class="hljs-number">110</span>, <span class="hljs-number">260</span>, <span class="hljs-number">40</span>, <span class="hljs-number">100</span>);
</code></pre>
<p>To create a 3D effect we need to use a linear gradient instead of solid color. Therefore, edit <em>canvas.js</em> and replace the previous code for drawing trunk with a new one:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">var</span> gradTrunk = ctx.createLinearGradient(<span class="hljs-number">110</span>, <span class="hljs-number">0</span>, <span class="hljs-number">150</span>, <span class="hljs-number">0</span>);

gradTrunk.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">"#22110c"</span>);
gradTrunk.addColorStop(<span class="hljs-number">0.5</span>, <span class="hljs-string">"#582b1f"</span>);
gradTrunk.addColorStop(<span class="hljs-number">1</span>, <span class="hljs-string">"#22110c"</span>);

ctx.fillStyle = gradTrunk;
ctx.fillRect(<span class="hljs-number">110</span>, <span class="hljs-number">260</span>, <span class="hljs-number">40</span>, <span class="hljs-number">100</span>);
</code></pre>
<p>The linear gradient can be created the same way as for the background in the previous tutorial. The gradient is changing color over <em>x</em> axis. We start dark brown at left side of the trunk <code>gradTrunk.addColorStop(0, "#22110c");</code>. At the middle we use lighter brown <code>gradTrunk.addColorStop(0.5, "#582b1f");</code> and the again the dark one on the right side of trunk <code>gradTrunk.addColorStop(1, "#22110c");</code>. Doing that we create an effect where the middle seems closer than the edges - it gives you a 3D feeling of the object.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829728728/G1aWZDWWu.png" alt="3dtrunk.PNG" /></p>
<h2 id="tree-with-texture">Tree with texture</h2>
<p>To give a little more textured feeling to our tree crown, we are also going to use a linear gradient. Instead of changing color in the gradient 2 or 3 times with different colors, we are going to switch between 2 shades of green very often. This will give the effect of corrugated cardboard, the way you (might) created your Christmas cards when you were a kid.
The drawing part (<code>moveTo</code>, <code>lineTo</code>) will stay the same.</p>
<p>So far you should have this code written to draw a tree crown's triangles:</p>
<pre><code class="lang-js">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawTriangle</span>(<span class="hljs-params">x, y</span>) </span>{

   ctx.fillStyle = <span class="hljs-string">"green"</span>;
   ctx.beginPath();
   ctx.moveTo(x, y);
   ctx.lineTo(x + <span class="hljs-number">100</span>, y<span class="hljs-number">-100</span>);
   ctx.lineTo(x + <span class="hljs-number">200</span>, y);
   ctx.fill();

}

drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">120</span>);
drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">190</span>);
drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">260</span>);
</code></pre>
<p>Let's add function parameter <em>fillColor</em> and define gradient from the top to the bottome of the tree crown:</p>
<pre><code class="lang-js">   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawTriangle</span>(<span class="hljs-params">x, y, fillColor</span>) </span>{
      ctx.fillStyle = fillColor;

      ctx.beginPath();

      ctx.moveTo(x, y);

      ctx.lineTo(x + <span class="hljs-number">100</span>, y<span class="hljs-number">-100</span>);

      ctx.lineTo(x + <span class="hljs-number">200</span>, y);

      ctx.fill();
   }


   <span class="hljs-comment">// background code</span>


   <span class="hljs-keyword">var</span> gradTree = ctx.createLinearGradient(<span class="hljs-number">0</span>, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">260</span>);

   <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> n = <span class="hljs-number">0</span>; n &lt; <span class="hljs-number">100</span>; n++) {

       <span class="hljs-keyword">var</span> decimal_number = n * <span class="hljs-number">0.01</span>

       <span class="hljs-keyword">if</span> (n%<span class="hljs-number">2</span> === <span class="hljs-number">0</span>) {
           gradTree.addColorStop(decimal_number, <span class="hljs-string">"#142f0e"</span>);
       } <span class="hljs-keyword">else</span> {
           gradTree.addColorStop(decimal_number, <span class="hljs-string">"#327321"</span>);
       }
   }

   drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">120</span>, gradTree); <span class="hljs-comment">//red triangle</span>
   drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">190</span>, gradTree); <span class="hljs-comment">//blue triangle</span>
   drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">260</span>, gradTree); <span class="hljs-comment">//green triangle</span>

}
</code></pre>
<p>As before, we need to define the gradient (<code>ctx.createLinearGradient(x0, y0, x1, y1)</code>. To create horizontal lines <em>xStart</em> and <em>xEnd</em> are set to 0. The first Y will be set at the top of the tree <em>y=20</em> and the second one at the bottom of the tree y=260. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606830232462/dt4utZKDT.png" alt="treeStructure.png" /></p>
<p>Using <em>for</em> loop we switch between darker (<code>#142f0e</code>) and lighter (<code>#327321</code>) green on every 0.01 - 100 times throughout the tree. When <em>n</em> is even, the color is a darker green, when odd the color is lighter green.
Because all values of <code>addColorStop</code> are between 0 (start of the gradient) and 1 (end of the gradient, we use n to calculate where in the gradient we are with our <code>addColorStop(value0to1, color)</code>. The generated gradient is used as an input parameter for the updated <em>drawTriangle</em> function.</p>
<h2 id="baubles">Baubles</h2>
<p>Let's try to give the baubles a 3D feeling too. Because baubles are in the shape of a circle, the 3D feeling can't be accomplished by a linear gradient. But there is another type of gradient that will give us the desired result - radial gradient.
It's created with a function <code>createRadialGradient(x0,y0,r0,x1,y1,r1)</code>.</p>
<p>It seems like there's a lot of parameters (6!). That's because you're creating 2 circles where each of them needs 3 parameters. The first three parameters are for the starting circle of the gradient and the last 3 parameters are for the second one.</p>
<p>Those 3 parameters are:</p>
<ul>
<li>x coordinate for the circle</li>
<li>y coordinate for the circle</li>
<li>radius</li>
</ul>
<p>Right now baubles are drawn using this <em>for</em> loop:</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> y = <span class="hljs-number">75</span>;

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">6</span>; i++) {

   ctx.beginPath();

   <span class="hljs-keyword">if</span> (i%<span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {

       ctx.fillStyle = <span class="hljs-string">'red'</span>;

       ctx.arc(<span class="hljs-number">110</span> , y, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);

       ctx.fill();

   } <span class="hljs-keyword">else</span> {

       ctx.fillStyle = <span class="hljs-string">'blue'</span>;

       ctx.arc(<span class="hljs-number">160</span>, y, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);

       ctx.fill();

   }

y = y + <span class="hljs-number">30</span>;

}
</code></pre>
<p>Update it to use a circular gradient for all the baubles:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">var</span> y = <span class="hljs-number">75</span>;

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">6</span>; i++) {

   ctx.beginPath();

   <span class="hljs-keyword">if</span> (i%<span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">var</span> gradient = ctx.createRadialGradient(<span class="hljs-number">110</span>, y, <span class="hljs-number">1</span>, <span class="hljs-number">110</span>, y, <span class="hljs-number">20</span>);

      gradient.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">'white'</span>);
      gradient.addColorStop(<span class="hljs-number">1</span>, <span class="hljs-string">`red`</span>);
       ctx.fillStyle = gradient;
       ctx.arc(<span class="hljs-number">110</span> , y, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);
       ctx.fill();
   } <span class="hljs-keyword">else</span> {
       <span class="hljs-keyword">var</span> gradient = ctx.createRadialGradient(<span class="hljs-number">160</span>, y, <span class="hljs-number">1</span>, <span class="hljs-number">160</span>, y, <span class="hljs-number">20</span>);

       gradient.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">'white'</span>);
       gradient.addColorStop(<span class="hljs-number">1</span>, <span class="hljs-string">`blue`</span>);
       ctx.fillStyle = gradient;
       ctx.arc(<span class="hljs-number">160</span>, y, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);
       ctx.fill();
   }

y = y + <span class="hljs-number">30</span>;

}
</code></pre>
<p>Gradient with two concetric circles <code>var gradient = ctx.createRadialGradient(160, y, 1, 160, y, 20);</code> improves 3D impression. baubles now change color from white <code>gradient.addColorStop(0, 'white');</code> in the center to red/blue <code>gradient.addColorStop(1,</code>blue<code>);</code>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829857811/sVKVba3Gu.png" alt="concentric_gradient.png" /></p>
<h3 id="improvement-of-the-3d-bauble">Improvement of the 3D bauble</h3>
<p>The baubles we created definitely look better than the old ones. But it could look more natural if the white circle would give the impression that the bauble is reflecting the light that is coming from the side. We can accomplish that by leaving the center of the second circle where it is (x1 = x1, y1 = y1) and moving the center of the first circle a little to the top (y0 = y0 - 10) right (x0 = x0 + 10).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829895723/xiCUIQvEr.png" alt="3dbauble.png" /></p>
<p>Let's edit baubles part to use eccentric circles to improve 3D design:</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> xRed = <span class="hljs-number">110</span>
<span class="hljs-keyword">var</span> xBlue = <span class="hljs-number">160</span>
<span class="hljs-keyword">var</span> y = <span class="hljs-number">75</span>
<span class="hljs-keyword">var</span> outerRadius = <span class="hljs-number">20</span>
<span class="hljs-keyword">var</span> innerRadius = <span class="hljs-number">1</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">6</span>; i++) {

   ctx.beginPath();

   <span class="hljs-keyword">if</span> (i % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {

       <span class="hljs-keyword">var</span> gradientRed = ctx.createRadialGradient(xRed, y, outerRadius, xRed + <span class="hljs-number">10</span>, y - <span class="hljs-number">10</span>, innerRadius);

       gradientRed.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">'red'</span>);
       gradientRed.addColorStop(<span class="hljs-number">1</span>, <span class="hljs-string">'white'</span>);

       ctx.fillStyle = gradientRed;
       ctx.arc(xRed, y, outerRadius, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);
       ctx.fill();

   } <span class="hljs-keyword">else</span> {

       <span class="hljs-keyword">var</span> gradientBlue = ctx.createRadialGradient(xBlue, y, outerRadius, xBlue + <span class="hljs-number">10</span>, y - <span class="hljs-number">10</span>, innerRadius);

       gradientBlue.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">'blue'</span>);
       gradientBlue.addColorStop(<span class="hljs-number">1</span>, <span class="hljs-string">'white'</span>);

       ctx.fillStyle = gradientBlue;
       ctx.arc(xBlue, y, outerRadius, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);
       ctx.fill();

   }

   y = y + <span class="hljs-number">30</span>;

}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829924226/GiHDE3pqn.png" alt="red_blue_3d_baubles.PNG" /></p>
<p>The tree looks adorable, but there is still a little room for improvement. Let's change the bauble colors from red/blue to random colors. Since we already created the function that provides a random color, this is easy. Instead of blue/red color for <code>addColorStop</code> for 0, call the <code>randomColor()</code> function.</p>
<p>Change <code>gradientBlue.addColorStop(0, 'blue');</code> to <code>gradientBlue.addColorStop(0, randomColor());</code> and change <code>gradientRed.addColorStop(0, 'red');</code> to <code>gradientRed.addColorStop(0, randomColor());</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606829957709/iodm1NR0R.png" alt="finnished_part2.PNG" /></p>
<h3 id="conclusion">Conclusion</h3>
<p>Isn't that tree you created yourself beautiful? And that giant stack of presents!</p>
<p>In this tutorial, you learned how to give a little more depth to your canvas creation with the usage of gradients.
For the circle-shaped objects, you can use <code>createRadialGradient</code> to give a feeling of light reflecting from the object.
You are not limited to only a few stops for the gradients, you can add as many as 100 (and more!) to create an interesting effect.</p>
<p>Besides the <code>fillRect</code> you already knew, you also learned about <code>strokeRect</code>. 
You need to use at least one of those if you want to create an object.
For both of those, you can choose separate colors.</p>
<p>You should also have got the basic idea of how to use math for drawing multiple objects on <code>canvas</code></p>
<p>This is not <code>canvas</code> related, but you also learned how to create a random RGB color code for your objects.
You can use that knowledge to apply random colors to your webpage elements.</p>
<p>And you created a piece of art, your mother would definitely hang on the fridge, if that would be possible (;</p>
]]></content:encoded></item><item><title><![CDATA[HTML Canvas Christmas tutorial - part 1: BASICS]]></title><description><![CDATA[What is HTML Canvas?
HTML's <canvas> element is a rectangular area for graphics. 
By default, it has no content. We can draw on it with JavaScript.
It is supported in all modern browsers and unlike flash, the user doesn't need to install any plugin.
...]]></description><link>https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-1-basics</link><guid isPermaLink="true">https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-1-basics</guid><category><![CDATA[HTML Canvas]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[canvas]]></category><category><![CDATA[ #2Articles1Week]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Mon, 30 Nov 2020 09:03:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606727255115/bTkYMc0Si.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="what-is-html-canvas">What is HTML Canvas?</h2>
<p>HTML's <code>&lt;canvas&gt;</code> element is a rectangular area for graphics. 
By default, it has no content. We can draw on it with JavaScript.
It is supported in all modern browsers and unlike flash, the user doesn't need to install any plugin.
It enables user interaction and more dynamic websites.
Check this <a target="_blank" href="https://codepen.io/thebabydino/pen/JXQyom">mesmerizing vortext</a> or this fun <a target="_blank" href="https://codepen.io/akm2/pen/rHIsa">interactive demo of gravity points</a>.
There are also many <a target="_blank" href="https://worldsbiggestpacman.com/play/">web games</a> created with HTML Canvas.</p>
<h2 id="what-will-you-learn-in-this-tutorial">What will you learn in this tutorial?</h2>
<p>Once you finish the tutorial, you will have the basic knowledge of HTML Canvas. 
You will know how to create 3 types of shapes - rectangle, triangle, and circle and how to position them on canvas. 
Moreover, you will learn how to create a linear-gradient background and will be able to write on canvas.</p>
<p>You also will have something to show - you will have a web Christmas card, that will look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606307893531/oot_Koo0X.png" alt="basic_christmas_card.PNG" /></p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>basic knowledge of HTML</li>
<li>basic knowledge of JavaScript (variables, functions, for loops)</li>
</ul>
<blockquote>
<p>To avoid confusion, in this tutorial you'll be using 'classic' JavaScript, ES5.</p>
</blockquote>
<h2 id="basics-of-canvas">Basics of Canvas</h2>
<p>To use canvas you need a pretty simple HTML file containing <code>&lt;canvas&gt;</code> element inside its body:</p>
<pre><code class="lang-html">
<span class="hljs-meta">&lt;!doctype <span class="hljs-meta-keyword">html</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>

   <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Awesome canvas<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canpic"</span> <span class="hljs-attr">width</span> = <span class="hljs-string">500;</span> <span class="hljs-attr">height</span> = <span class="hljs-string">450;</span>&gt;</span>
    Your browser does not support the canvas element.
<span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The attribute <em>id</em> is set on <code>&lt;canvas&gt;</code> so it can be referenced from JavaScript. We also set width and height on the element, although you could also set them via JS.</p>
<p>The <em>Your browser does not support the canvas element.</em> between <code>&lt;canvas&gt;</code> and <code>&lt;/canvas&gt;</code> is shown in older browsers that don't support canvas.</p>
<blockquote>
<p>Read more about <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Graceful_degradation">graceful degradation</a>.</p>
</blockquote>
<p>HTML canvas works like a real-world canvas, except rather than an oil painting it is a pixel painting. A circle you drew on canvas is just like dried paint - its pixels replaced everything that was there before. That circle can't be moved or remolded into something else.</p>
<p>Don't worry if that is hard to grip. Just keep it in mind while you follow this tutorial. So let's get our hands dirty.</p>
<h2 id="christmas-card">Christmas card</h2>
<p>Our Christmas card will consist of:</p>
<ol>
<li><p>A Christmas tree - 3 identical overlapping <a target="_blank" href="https://www.w3schools.com/tags/canvas_lineto.asp">triangles</a> to form a tree crown and a <a target="_blank" href="https://www.w3schools.com/tags/canvas_fillrect.asp">square</a> for a trunk. We'll create two functions. The first one, that draws a triangle - it's called 3 times with different coordinates. And the second one that draws a square (to get a trunk).</p>
</li>
<li><p>There will be 6 baubles of 2 different colors on the tree. We will draw them as circles with <a target="_blank" href="https://www.w3schools.com/tags/canvas_arc.asp">arc</a>.</p>
</li>
<li><p>A background will be blue on the top, white in the middle, and green on the bottom.
We will use <a target="_blank" href="https://www.w3schools.com/tags/canvas_createlineargradient.asp">linear gradient</a>.</p>
</li>
<li><p>On the green, underneath the tree, we'll write a <a target="_blank" href="https://www.w3schools.com/tags/canvas_filltext.asp">message</a>.</p>
</li>
</ol>
<h3 id="the-tree">The tree</h3>
<p>First, create a new folder named Canvas. Inside that folder create an HTML file named <em>canvas.html</em> with a container for canvas:</p>
<pre><code class="lang-html">
<span class="hljs-meta">&lt;!doctype <span class="hljs-meta-keyword">html</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>

   <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Awesome canvas<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canpic"</span> <span class="hljs-attr">width</span> = <span class="hljs-string">500;</span> <span class="hljs-attr">height</span> = <span class="hljs-string">450;</span>&gt;</span>
    Your browser does not support the canvas element.
<span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"canvas.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It's the same content as above mentioned basic canvas HTML example with the added import of javascript file named <em>canvas.js</em> at the end of the body.</p>
<p>Next, create <em>canvas.js</em> file next to <em>canvas.html</em>.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canpic"</span>); <span class="hljs-comment">// get canvas element from HTML by ID</span>
<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>);
</code></pre>
<p>First, we need to prepare our canvas for drawing. We do this by <code>getContext</code> method, which returns the drawing context on the canvas. It takes two arguments- context type and context attributes if there are any. We'll be drawing in two dimensions so we select <em>2d</em> without any context attributes.</p>
<blockquote>
<p>You can read more about <code>getContext</code> method <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext">here</a></p>
</blockquote>
<p>Next, let's draw a green triangle:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606312427883/YYrY1UWDH.png" alt="firstTriangle(1).png" /></p>
<pre><code class="lang-js">
<span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canpic"</span>);  <span class="hljs-comment">// get canvas element from HTML by ID</span>

<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>);

ctx.fillStyle = <span class="hljs-string">"green"</span>;

ctx.beginPath();

ctx.moveTo(<span class="hljs-number">30</span>, <span class="hljs-number">120</span>);

ctx.lineTo(<span class="hljs-number">130</span>, <span class="hljs-number">20</span>);

ctx.lineTo(<span class="hljs-number">230</span>, <span class="hljs-number">120</span>);

ctx.fill();
</code></pre>
<p>First, we set our fill color to green. Second, we start drawing with <a target="_blank" href="https://www.w3schools.com/tags/canvas_beginpath.asp">beginPath</a>. Using method <a target="_blank" href="https://www.w3schools.com/tags/canvas_moveto.asp">moveTo(x, y)</a> triangle starts we start drawing triangle in its bottom left corner located at <em>y = 120</em> and <em>x = 30</em>.Triangle's top point will be at <em>y = 20</em> and <em>x = 130</em>. The rightmost point will be at the same height as the first one but furthest to the right. Open <em>canvas.html</em> in the browser to see the green triangle you've just drawn.</p>
<blockquote>
<p>Drawing in canvas starts at the top left corner and progress to the bottom right corner. The bigger the <em>x</em> is, the more you are to the right. The bigger the <em>y</em> is, the more you are to the bottom.</p>
</blockquote>
<p>So far there is only one triangle but we need t(h)ree of them! We're programmers, we're not gonna write all this code 3 times. So let's wrap the drawing of the triangle into a function:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canpic"</span>);  <span class="hljs-comment">// get canvas element from HTML by ID</span>

<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>);


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawTriangle</span>(<span class="hljs-params">x, y</span>) </span>{

ctx.fillStyle = <span class="hljs-string">"green"</span>;

ctx.beginPath();

ctx.moveTo(x, y);

ctx.lineTo(x + <span class="hljs-number">100</span>, y<span class="hljs-number">-100</span>);

ctx.lineTo(x + <span class="hljs-number">200</span>, y);

ctx.fill();

}
</code></pre>
<p>Instead of hardcoded numbers, there are <em>x</em> and <em>y</em> for our starting point. The other 2 points we calculate based on the first point, the same way we did before. Now we'll call that function 3 times to draw a tree crown like this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606311275296/GmDPDN4Gz.png" alt="treeCrown.png" /></p>
<p>So let's draw:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canpic"</span>);  <span class="hljs-comment">// get canvas element from HTML by ID</span>

<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>);


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawTriangle</span>(<span class="hljs-params">x, y</span>) </span>{
  ctx.fillStyle = <span class="hljs-string">"green"</span>;

  ctx.beginPath();

  ctx.moveTo(x, y);

  ctx.lineTo(x + <span class="hljs-number">100</span>, y<span class="hljs-number">-100</span>);

  ctx.lineTo(x + <span class="hljs-number">200</span>, y);

  ctx.fill();
}


drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">120</span>); <span class="hljs-comment">//red triangle</span>

drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">190</span>); <span class="hljs-comment">//blue triangle</span>

drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">260</span>); <span class="hljs-comment">//green triangle</span>
</code></pre>
<p>We are drawing the triangles one below the other, so x is the same. For x and y of the first triangle, we'll take the same values as for a single triangle in the initial example. The next two triangles will be positioned below the first one. Refresh your <em>canvas.html</em> in the browser. You should see the tree crown of the Christmas tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606308307724/vAqDGucOu.png" alt="treeCrownDrawn.PNG" /></p>
<p>The only thing missing is the square trunk. We draw squares with the function <code>fillRect(x, y, width, height)</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606311177824/Zu8d89YWL.png" alt="treeTrunk.png" /></p>
<p>The trunk will be touching the lowest triangle of the tree crown. Half the trunk will be to the left of the middle of the tree and half to the right. So we set x value to <em>middleOfTheTree - halfWidthOfTheTrunk</em>. We'll also need to change the color. To add the trunk just add this part at the end of <em>canvas.js</em>:</p>
<pre><code class="lang-js">ctx.fillStyle = <span class="hljs-string">"brown"</span>;
ctx.fillRect(<span class="hljs-number">110</span>, <span class="hljs-number">260</span>, <span class="hljs-number">40</span>, <span class="hljs-number">100</span>);
</code></pre>
<p>Refresh your browser to see the full tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606308363761/_qi1fdueE.png" alt="justTree.PNG" /></p>
<p>Congratulations, you've just drawn your first picture with HTML canvas!</p>
<h2 id="the-decorations">The decorations</h2>
<p>The tree doesn't look very festive yet. We need to decorate it! We are going to create 6 baubles - 3 colored red and 3 colored blue. Red ones will go to the left and blue ones to the right.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606308607657/GbY1Ea-aR.jpeg" alt="baubles.jpg" /></p>
<p>Let's add drawing of the baubles at the end of <em>canvas.js</em>:</p>
<pre><code><span class="hljs-string">var</span> <span class="hljs-string">y</span> <span class="hljs-string">=</span> <span class="hljs-number">75</span><span class="hljs-string">;</span>

<span class="hljs-string">for</span> <span class="hljs-string">(var</span> <span class="hljs-string">i</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">&lt;</span> <span class="hljs-number">6</span><span class="hljs-string">;</span> <span class="hljs-string">i++)</span> {

   <span class="hljs-string">ctx.beginPath();</span>

   <span class="hljs-string">if</span> <span class="hljs-string">(i%2</span> <span class="hljs-string">==</span> <span class="hljs-number">0</span><span class="hljs-string">)</span> {

       <span class="hljs-string">ctx.fillStyle</span> <span class="hljs-string">=</span> <span class="hljs-string">'red'</span><span class="hljs-string">;</span>

       <span class="hljs-string">ctx.arc(110</span> , <span class="hljs-string">y</span>, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> <span class="hljs-string">*</span> <span class="hljs-string">Math.PI);</span>

       <span class="hljs-string">ctx.fill();</span>

   } <span class="hljs-string">else</span> {

       <span class="hljs-string">ctx.fillStyle</span> <span class="hljs-string">=</span> <span class="hljs-string">'blue'</span><span class="hljs-string">;</span>

       <span class="hljs-string">ctx.arc(160</span>, <span class="hljs-string">y</span>, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> <span class="hljs-string">*</span> <span class="hljs-string">Math.PI);</span>

       <span class="hljs-string">ctx.fill();</span>

   }

<span class="hljs-string">y</span> <span class="hljs-string">=</span> <span class="hljs-string">y</span> <span class="hljs-string">+</span> <span class="hljs-number">30</span><span class="hljs-string">;</span>

}
</code></pre><p>We use for loop to draw 6 baubles. Even loop numbers will create red baubles on the left and odd numbers will create the blue ones. We use <a target="_blank" href="https://www.tutorialspoint.com/What-is-Modulus-Operator-in-JavaScript">modulus</a> operator to check whether <code>i</code> is even. Depending on that, we choose fillStyle and position(x, y) of the circle. We create circle shape with <a target="_blank" href="https://www.w3schools.com/tags/canvas_arc.asp">arc()</a> method. We create a circle by starting a curve on 0 and ending it on 2*Math.PI. Each time, we need to increase <code>y</code> for 30, no matter the color of the bauble to move down.</p>
<blockquote>
<p>arc(x, y, radius, startAngle, endAngle) method creates a curve, that can be, but is not necessarily, a circle. Both angles must be in <em>radians</em>. 2 * Math.PI of radians is the same as 360°</p>
</blockquote>
<p>Congratulations, your tree is now decorated!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606308647916/WZKYGJ6ss.png" alt="withbulbs.PNG" /></p>
<h2 id="background">Background</h2>
<p>Background can be created with <a target="_blank" href="https://www.w3schools.com/tags/canvas_createlineargradient.asp">linear gradient</a>. We'll start with blue for the sky on the top, green for the grass on the bottom. Because the gradient between those 2 colors would look terrible, we'll create a 'sun-just-went-down' effect and put white in the middle.</p>
<p>Add this at the end of <em>canvas.js</em>:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">var</span> backgroundLinear = ctx.createLinearGradient(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">350</span>);

backgroundLinear.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">"#151c2e"</span>);

backgroundLinear.addColorStop(<span class="hljs-number">0.9</span>, <span class="hljs-string">"white"</span>);

backgroundLinear.addColorStop(<span class="hljs-number">1</span>,<span class="hljs-string">"green"</span>);

ctx.fillStyle = backgroundLinear;

ctx.fillRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">500</span>, <span class="hljs-number">450</span>);
</code></pre>
<p>We create gradient with <a target="_blank" href="https://www.w3schools.com/tags/canvas_createlineargradient.asp">createLinearGradient(xStart, yStart, xEnd, yEnd)</a> method. Because we want gradient from top to bottom, we set beginning coordinates at 0. Because we don't want the gradient tilted we leave the <em>xEnd</em> at 0. To have a grass effect we stop the gradient at 350 which is before the end of the image at 450. The color of the background between the gradient end image end will be filled with solid green. For each color, we add a <a target="_blank" href="https://www.w3schools.com/tags/canvas_addcolorstop.asp">addColorStop(color, position between start(0) and end(1) of gradient)</a> method. You already used <em>fillStyle</em> for objects we draw before. This time, instead of some color, we select previously created <em>backgroundLinear</em>. We use <em>fillRect</em> to draw the background on the canvas.</p>
<p>Refresh your browser. What happened? Everything we draw before disappeared! In the beginning, we talked about pixels being completely replaced - that's what I was talking about. Just like with the real-world canvas, if you first create some shapes and then the background, shapes are not seen anymore. Don't worry, that's easy to fix. You just have to move the background code on the top - before the tree is drawn:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"canpic"</span>);  <span class="hljs-comment">// get canvas element from HTML by ID</span>

<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>);


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawTriangle</span>(<span class="hljs-params">x, y</span>) </span>{
  ctx.fillStyle = <span class="hljs-string">"green"</span>;

  ctx.beginPath();

  ctx.moveTo(x, y);

  ctx.lineTo(x + <span class="hljs-number">100</span>, y<span class="hljs-number">-100</span>);

  ctx.lineTo(x + <span class="hljs-number">200</span>, y);

  ctx.fill();
}


<span class="hljs-keyword">var</span> backgroundLinear = ctx.createLinearGradient(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">350</span>);

backgroundLinear.addColorStop(<span class="hljs-number">0</span>, <span class="hljs-string">"#151c2e"</span>);

backgroundLinear.addColorStop(<span class="hljs-number">0.9</span>, <span class="hljs-string">"white"</span>);

backgroundLinear.addColorStop(<span class="hljs-number">1</span>,<span class="hljs-string">"green"</span>);

ctx.fillStyle = backgroundLinear;

ctx.fillRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">500</span>, <span class="hljs-number">450</span>);


drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">120</span>); <span class="hljs-comment">//red triangle</span>

drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">190</span>); <span class="hljs-comment">//blue triangle</span>

drawTriangle(<span class="hljs-number">30</span>, <span class="hljs-number">260</span>); <span class="hljs-comment">//green triangle</span>


ctx.fillStyle = <span class="hljs-string">"brown"</span>;
ctx.fillRect(<span class="hljs-number">110</span>, <span class="hljs-number">260</span>, <span class="hljs-number">40</span>, <span class="hljs-number">100</span>);

<span class="hljs-keyword">var</span> y = <span class="hljs-number">75</span>;

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">6</span>; i++) {

   ctx.beginPath();

   <span class="hljs-keyword">if</span> (i%<span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {

       ctx.fillStyle = <span class="hljs-string">'red'</span>;

       ctx.arc(<span class="hljs-number">110</span> , y, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);

       ctx.fill();

   } <span class="hljs-keyword">else</span> {

       ctx.fillStyle = <span class="hljs-string">'blue'</span>;

       ctx.arc(<span class="hljs-number">160</span>, y, <span class="hljs-number">20</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);

       ctx.fill();

   }

y = y + <span class="hljs-number">30</span>;

}
</code></pre>
<p>Refresh your browser again, you should see the tree on the background you've just added.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606308690976/RtR9SlLhd.png" alt="withBG.PNG" /></p>
<h2 id="greeting">Greeting</h2>
<p>When we are creating a Christmas card, we want to write some good wishes on it! Fortunately, canvas has a simple method to do that. All the shapes you created on canvas (rectangle, arc, and text) can be drawn in two ways. You can either draw them filled with color (so far we used that) or just stroke their shape out. You can also do both.</p>
<p>Let's add <em>Merry Christmas</em> to your card by adding this code to the end of <em>canvas.js</em>:</p>
<pre><code class="lang-js">
ctx.strokeStyle = <span class="hljs-string">'white'</span>;

ctx.fillStyle = <span class="hljs-string">'red'</span>;

ctx.lineWidth = <span class="hljs-number">1</span>;

ctx.font = <span class="hljs-string">'40px arial'</span>;

ctx.strokeText(<span class="hljs-string">'Merry Christmas!'</span>, <span class="hljs-number">30</span>, <span class="hljs-number">410</span>);

ctx.fillText(<span class="hljs-string">'Merry Christmas!'</span>, <span class="hljs-number">30</span>, <span class="hljs-number">410</span>);
</code></pre>
<p>First, we select a color for stroke. Then we select fill color. after that, we select <em>lineWidth</em> for the stroke and the font family.Finally we create stroked  <a target="_blank" href="https://www.w3schools.com/tags/canvas_stroketext.asp">strokeText(text, x, y)</a>) and filled (<a target="_blank" href="https://www.w3schools.com/tags/canvas_filltext.asp">fillText(text, x, y)</a>) text.</p>
<blockquote>
<p>You can see the whole code <a target="_blank" href="https://gitlab.com/GirlThatLovesToCode/christmascanvas">here</a>.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606308877814/jsvMzBg8W.png" alt="basic_christmas_card.PNG" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to create 4 types of elements:</p>
<ol>
<li>triangle with commands:<ul>
<li>beginPath()</li>
<li>moveTo(x, y)</li>
<li>lineTo(x, y)</li>
</ul>
</li>
<li>rectangle with a command:<ul>
<li>fillRect(x, y, w, h)</li>
</ul>
</li>
<li>circle with a command:<ul>
<li>arc(x, y, radius, startAngle, endAngle)</li>
</ul>
</li>
<li>text with commands:<ul>
<li>strokeText(text, x, y)</li>
<li>fillText('text', x, y)</li>
</ul>
</li>
</ol>
<p>You also learned that you need to select fill color if you want your shape to be visible on the canvas.
You can color it 2 ways:</p>
<ol>
<li>Fill color:<ul>
<li>fillStyle(color)</li>
</ul>
</li>
<li>Gradient<ul>
<li>createLinearGradient(0(xStart, yStart, xEnd, yEnd));</li>
<li>backgroundLinear.addColorStop(color, position beetween start(0) and end(1));</li>
<li>fillStyle(gradient)</li>
</ul>
</li>
</ol>
<p>Besides that, you've also learned how to use basic shapes like triangles to draw more complex shapes like a tree crown.</p>
<p>And let's not forget, that you've just created a beautiful Christmas card that you can share with your close ones.</p>
<blockquote>
<p>What's Christmas without gifts? You can learn how to create them and much more in <a target="_blank" href="https://girlthatlovestocode.com/html-canvas-christmas-tutorial-part-2-repetition-and-depth">Part 2</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[CSS pseudo-elements: `before` and `after`]]></title><description><![CDATA[My first job was at a firm that created custom websites.
They mostly looked awesome and were CSS-heavy. I was an hour into my first day when I already encountered a ::before - something a junior rarely uses at home when learning and it's hard to grip...]]></description><link>https://girlthatlovestocode.com/css-pseudo-elements-before-and-after</link><guid isPermaLink="true">https://girlthatlovestocode.com/css-pseudo-elements-before-and-after</guid><category><![CDATA[CSS3]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Thu, 12 Nov 2020 13:51:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187166481/YcU2uf4SA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>My first job was at a firm that created custom websites.
They mostly looked awesome and were CSS-heavy. I was an hour into my first day when I already encountered a <code>::before</code> - something a junior rarely uses at home when learning and it's hard to grip at if no one explains it to you.</p>
<p>Few weeks passed with copy-pasting the <code>::before</code> CSS from other projects, but then I got it and it wasn't that difficult to use.
But copy-pasting something you don't understand is never a good idea. That's
why I gathered most of the information about <code>::before</code> and <code>::after</code> in this blog.
So you won't be in a position of copy-pasting without understanding as I was doing it
and because <code>::before</code> is pretty awesome when you got to know it.
There are endless possibilities for creation with it when you're comfortable using it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187638213/axSljrzlC.png" alt="main.PNG" /></p>
<h2 id="what-will-i-learn">What will I learn</h2>
<p>At first, we will review the pseudo-elements, the difference between <code>before</code> and <code>after</code>.
The main property of a <code>before</code>/<code>after</code> selector is a <code>content</code>. There are many possibilities for its value and in the second part of this blog, we will review some of them:</p>
<ol>
<li>a string</li>
<li>an attribute</li>
<li>an image</li>
<li>nothing</li>
</ol>
<p>For each value, I provided at least one showcase that should give you a fair picture of what's going on.</p>
<p>This is not a tutorial, showcases are not explained in depth.
I suggest you copy-paste (or, even better, retype) each of the showcases and play with it a little, it will help you to understand those two <code>pseudo-elements</code> better.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ol>
<li>Basic knowledge of HTML</li>
<li>Basic knowledge of CSS</li>
</ol>
<h2 id="pseudo-elements">Pseudo-elements</h2>
<p>Pseudo-element is an element that doesn't exist in the document tree but appears on the page as it would.
To simplify -  pseudo-element (like <code>::before</code>) is a 'faker' that pretends to be there, but it isn't.</p>
<p><code>::before</code> and <code>::after</code> leaves your markup semantic, but at the same time they give you a lot of extra design possibilities.
Think of them as two extra tickets to add cosmetic content to an element.</p>
<blockquote>
<p>Besides <code>::before</code> and <code>::after</code>, other pseudo-elements are: <code>::first-letter</code>, <code>::first-line</code> and <code>::selection</code>.
They behave a little differently though because you aren't creating new content. 
Rather, you're selecting only a part of a tag, it's like creating a non-existing <code>span</code>.</p>
</blockquote>
<p>You might expect them to be before or after the element, but that's not the case. 
Pseudo-element is the first child of the selected element. That means they appear inside the element, next to its content.</p>
<p>They have few negative sides though:</p>
<ul>
<li>you can’t attach an event only to a pseudo-element</li>
<li>most screen readers read the content of a pseudo-element (<a target="_blank" href="https://www.stefanjudis.com/today-i-learned/css-content-accepts-alternative-text/">here</a> is a solution for that, but it doesn't work on most browsers)</li>
<li>you usually can't select it </li>
</ul>
<blockquote>
<p>You can't create <code>::before</code> or <code>::after</code> on the self-closing tags. So <code>&lt;img /&gt;</code>, <code>&lt;input /&gt;</code> or <code>&lt;hr /&gt;</code> can't
have <code>::before</code>!</p>
</blockquote>
<p>Here's how that looks in practice:</p>
<p><strong>HTML</strong></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"myelement"</span>&gt;</span>
    Text in "myelement".
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><strong>CSS</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.myelement</span> {
    <span class="hljs-attribute">color</span>: red;
}
<span class="hljs-selector-class">.myelement</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">"I'm before"</span>;
}
</code></pre>
<p><strong>Browser</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187708640/XK91ofxJ-.png" alt="browser.PNG" /></p>
<p><strong>Page source</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187725710/-RbJoU-it.png" alt="before.PNG" /></p>
<p>As you see, both texts are visible in the browser. But the <code>::before</code> text isn't visible in the page source.
Also, we set the color to red on <code>.myelement</code> and <code>::before</code> inherited it.</p>
<h2 id="before-or-after">::before or ::after?</h2>
<p><code>::before</code> and <code>::after</code> behave very similar.
The only difference is how they position themselves in the browser and the page source.</p>
<p><strong>Page source</strong>
<code>::before</code> appears before the content of the child and <code>::after</code> appears after it.
They are both <strong>inside</strong> the element.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187761768/Fl_hIquKC.png" alt="beforeaftersource.PNG" /></p>
<p><strong>Browser</strong></p>
<p>If we don't manipulate their position, naturally <code>::before</code> comes <em>before</em> the element's content
and <code>::after</code> comes <em>after</em> it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187777331/RI0dPAsKx.png" alt="beforeafterbrowser.PNG" /></p>
<p>You can choose between those two based on where are you trying to put the additional element, but it's not necessary.</p>
<p><strong>FontAwesome icon <code>::before</code> the element</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187797515/309Gb2c0L.png" alt="beforeicon.PNG" /></p>
<p><strong>FontAwesome icon <code>::after</code> the element</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187814663/BPJ2hmgZk.png" alt="aftericon.PNG" /></p>
<blockquote>
<p>Since <code>::before</code> and <code>::after</code> are pretty much the same, I'm going to use only the <code>::before</code> for the rest of the tutorial. Whatever I write for the <code>::before</code> goes the same for the <code>::after</code> too!</p>
</blockquote>
<h3 id="stacked">Stacked</h3>
<p>However, if <code>::before</code> and <code>::after</code> are stacked on top of each other, the <code>::after</code> will be positioned on the top of <code>before</code>.
If we create two squares of different colors and sizes and position them on top of each other, the <code>::after</code> square (blue) will cover part of the <code>::before</code> square (orange).
That's because the <code>after</code> is later in source-order.</p>
<p><strong>CSS</strong></p>
<pre><code class="lang-css">               <span class="hljs-selector-class">.myelement</span><span class="hljs-selector-pseudo">::before</span> {
                   <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
                   <span class="hljs-attribute">width</span>: <span class="hljs-number">50px</span>;
                   <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
                   <span class="hljs-attribute">background-color</span>: orange;
                   <span class="hljs-attribute">position</span>: absolute;
                   <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
               }

               <span class="hljs-selector-class">.myelement</span><span class="hljs-selector-pseudo">::after</span> {
                   <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
                   <span class="hljs-attribute">width</span>: <span class="hljs-number">30px</span>;
                   <span class="hljs-attribute">height</span>: <span class="hljs-number">30px</span>;
                   <span class="hljs-attribute">background-color</span>: blue;
                   <span class="hljs-attribute">position</span>: absolute;
                   <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
               }
</code></pre>
<p><strong>Browser</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605187907907/8XIyV_6Tk.png" alt="sameposition.PNG" /></p>
<p>As you can see, the orange <code>::before</code> square is partly covered by the blue <code>::after</code> square.</p>
<blockquote>
<p>For now, don't fuss if you don't know what is going on, we'll cover that later on.
This is just to show you the difference between <code>::before</code> and <code>::after</code></p>
</blockquote>
<h2 id="before-or-before">:before or ::before?</h2>
<p>At first, there was <strong><code>:before</code></strong>.
Later, they distinguished between pseudo elements and pseudo selectors (eg. `:first-child).</p>
<ul>
<li><strong>pseudo-elements</strong> have <strong>double-colon</strong> selectors(<code>::</code>)</li>
<li><strong>pseudo-selectors</strong> have <strong>single-colon</strong> selectors (<code>:</code>)</li>
</ul>
<p><code>before</code> is a pseudo-element, so you should use <code>::</code> if you want to do it right.</p>
<p>BUT - enters Internet Explorer.
Internet Explorer 8 and below only supports <code>:</code></p>
<p><strong>All modern browsers support it both ways</strong>, so if you need to support old IE or you're just used to it,
you can use <code>:before</code>, no fuss.</p>
<h2 id="possible-values-for-content">Possible values for content</h2>
<p>The most important part of <code>::before</code> is the <code>content</code>.
Content can be a lot of things:</p>
<ol>
<li><strong>a string</strong></li>
<li><strong>an attribute</strong></li>
<li><strong>an image</strong></li>
<li><strong>nothing</strong></li>
<li>open-quote and close-quote</li>
<li>no-open-quote | no-close-quote</li>
<li>counter()</li>
<li>alternative text</li>
</ol>
<p>Here I'll showcase the ones I think are the most useful. </p>
<h3 id="string">String</h3>
<p>That one is pretty straightforward. You can use a string and it can contain unicode special characters.</p>
<blockquote>
<p>Special characters need to be specially encoded as a unicode entity.
Check the  ASCII code for the chosen character <a target="_blank" href="https://css-tricks.com/snippets/html/glyphs/">here</a>
and convert it to CSS value here: http://www.evotech.net/articles/testjsentities.html</p>
</blockquote>
<h4 id="showcase-comment">Showcase:  Comment</h4>
<p>Add a string 'Comment' before each comment on a blog.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"comment"</span>&gt;</span>
    That post is great!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css">        <span class="hljs-selector-class">.comment</span><span class="hljs-selector-pseudo">::before</span> {
            <span class="hljs-attribute">content</span>: <span class="hljs-string">"Comment: "</span>;
        }
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188032792/3As80qHc1.png" alt="Comment.PNG" /></p>
<h4 id="showcase-copyright">Showcase: Copyright</h4>
<p>Add a copyright special character before an author of a page.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"copyright"</span>&gt;</span>
    GirlThatLovesToCode
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css">     <span class="hljs-selector-class">.copyright</span><span class="hljs-selector-pseudo">::before</span> {
            <span class="hljs-attribute">content</span>: <span class="hljs-string">"\00A9"</span>;
     }
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188057583/U1WlqAFiC.png" alt="copyright.PNG" /></p>
<h3 id="attribute">Attribute</h3>
<p>You have access to the parent element's (the one you're creating <code>::before</code> on) attributes and can use them as the content for the <code>::before</code>.</p>
<blockquote>
<p><a target="_blank" href="https://www.w3schools.com/html/html_attributes.asp">Here</a> is the list of all possible attributes.</p>
</blockquote>
<h4 id="showcase-show-the-whole-link-on-hover">Showcase: Show the whole link on hover</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://girlthatlovestocode.com/"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"linkOnHover"</span>&gt;</span>Check this awesome link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-id">#linkOnHover</span><span class="hljs-selector-pseudo">:hover</span><span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">": "</span> <span class="hljs-built_in">attr</span>(href);
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188085361/tJEv79xOo.png" alt="hoverHref.PNG" /></p>
<p>As you can see, you can bind <code>::after</code> <strong>just</strong> on <code>:hover</code> too!</p>
<h3 id="image">Image</h3>
<p>You can show an image in your <code>::before</code>. This is so useful for styling (eg. lists)!
Because gradients are essentially images, the same rule applies to them. </p>
<blockquote>
<p>The image is inserted at its exact dimensions and can't be resized.</p>
</blockquote>
<h4 id="showcase-ducky">Showcase: Ducky</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"rubber-duck"</span>&gt;</span>
    In software engineering, <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>rubber duck<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> debugging is a method of debugging code. The name is a reference to a story in the book The Pragmatic Programmer in which a programmer would carry around a <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>rubber duck<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> and debug their code by forcing themselves to explain it, line-by-line, to the <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>duck<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>.
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.rubber-duck</span> <span class="hljs-selector-tag">span</span><span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"duck.png"</span>);
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188183511/nQ0OrqEpN.png" alt="duckie.PNG" /></p>
<h4 id="showcase-gradient">Showcase: Gradient</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"gradiented"</span>&gt;</span>
    You can even use gradient as an image!
    Nullam in enim id leo mollis dapibus. Ut eget arcu nunc. Proin in purus accumsan, elementum felis ut, mollis tellus.
[... There is more text on the image]
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.gradiented</span> {
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">500px</span>;
}

<span class="hljs-selector-class">.gradiented</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-built_in">linear-gradient</span>(to bottom, red, yellow);
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">z-index</span>: -<span class="hljs-number">1</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188210125/WgH-0c45x.png" alt="gradient.PNG" /></p>
<p>Here is a little more going on than on the rest of the showcases.
Position, width, and height on <code>::before</code> are all needed for the gradient to be visible.
If you drop any of those, the gradient won't be visible.
We added a z-index so the gradient doesn't cover the text. It's sent to the background instead.
Because absolute positioned element is positioned regarding the first positioned element, we had to set the position
for its parent element.</p>
<h3 id="nothing">Nothing</h3>
<p>You might want to create something with CSS, not just set your content to something (eg. image in the background, so you can resize it).
In that case, you can't just exclude <code>content</code> - there is no <code>::before</code> without content. 
You will want to set the content to an empty string.</p>
<blockquote>
<p>Comment out the properties that you're not sure why they are here. You'll see what changes.</p>
</blockquote>
<h4 id="showcase-image-as-a-background">Showcase: Image as a background</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"img-bg"</span>&gt;</span>
    I want to have an image on the left side of the text. But my image is too big and I can't resize it if I put it in the content.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.img-bg</span> {
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">300px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
}

<span class="hljs-selector-class">.img-bg</span><span class="hljs-selector-pseudo">::before</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(circle-cropped.png);
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
    <span class="hljs-attribute">background-size</span>: cover;
    <span class="hljs-attribute">left</span>: -<span class="hljs-number">120px</span>;
    <span class="hljs-attribute">top</span>: -<span class="hljs-number">30px</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188248479/N2tp4Ut11.png" alt="bgImage.PNG" /></p>
<p>We've set the div's width and height, so it looks better. As in some cases before,
it's <code>position</code> is set to <code>relative</code> so we can position the <code>::before</code> absolutely.
If the content is empty, you need to set <code>position</code> as <code>absolute</code> if you want the background to be visible.
When working with <code>background</code>, you have to set <code>width</code>, <code>height</code>, and <code>background-size</code> for the background to be visible.
<code>left</code> and <code>top</code> just covers the cosmetics - so the image is where it should be.</p>
<h4 id="showcase-speech-buble">Showcase: Speech buble</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"speech"</span>&gt;</span>My name is GirlThatLovesToCode. That's becouse I'm a girl and I love to code.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.speech</span>{
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">500px</span>;
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#add8e6</span>;
    <span class="hljs-attribute">margin</span>: auto;
}

<span class="hljs-selector-class">.speech</span><span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">left</span>: -<span class="hljs-number">30px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">border-width</span>: <span class="hljs-number">30px</span> <span class="hljs-number">30px</span> <span class="hljs-number">0</span>;
    <span class="hljs-attribute">border-style</span>: solid;
    <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#add8e6</span> transparent;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188442015/EBjMah7EM.png" alt="speech.PNG" /></p>
<p>I won't explain the creating of a speech bubble here as that could be a whole new tutorial.
Just notice the <code>position</code>s that are set and that <code>::after</code> has no content. 
The only thing that exists in there, is a border that is shaped into a triangle.</p>
<blockquote>
<p><a target="_blank" href="https://projects.verou.me/bubbly/">Here</a> you can create your speech bubbles and play with it.</p>
</blockquote>
<h4 id="extra-combine-the-before-and-after">Extra: Combine the before and after</h4>
<p>Once you're familiar with the possibilities that <code>::before</code> and <code>::after</code> offers you,
you can combine them.</p>
<p>If you just add the previously created class <code>img-bg</code> you created before, to the <code>div</code> with 
class <code>speech</code>, like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"speech img-bg"</span>&gt;</span>My name is GirlThatLovesToCode. That's because I'm a girl and I love to code.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>and you make no change to the existing CSS, this is what you get:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1605188562301/nTS0QlXpw.png" alt="speechandimgbg.PNG" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Now you should have a better understanding of pseudo-elements <code>::before</code> and <code>::after</code>. 
They are a great way to upgrade your styling, but should never be used for the actual content of your webpage.
The most important part of <code>::before</code> is <code>content</code>.
Depending on what you're trying to achieve, you select one of the possible values for <code>content</code>.
You can style your <code>::before</code> with the same CSS rules as you would style any other element.
Keep in mind that the showcases were just examples, used to show the ideas, how you use <code>::before</code>
 is dependant on your design.</p>
]]></content:encoded></item><item><title><![CDATA[Rookie – ‘Your first days on the job’ tips]]></title><description><![CDATA[Everybody is lost on their first days on the job. Even the most senior programmer I know, who changed tons of jobs (because they weren't challenging enough) and was in charge of many developers in his own firm, said he always feels like an imposter o...]]></description><link>https://girlthatlovestocode.com/first-days-on-the-job-tips</link><guid isPermaLink="true">https://girlthatlovestocode.com/first-days-on-the-job-tips</guid><category><![CDATA[job]]></category><category><![CDATA[newbie]]></category><category><![CDATA[tips]]></category><category><![CDATA[Experience ]]></category><dc:creator><![CDATA[GirlThatLovesToCode]]></dc:creator><pubDate>Mon, 26 Oct 2020 13:24:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1604410545583/1H4LBt-x3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Everybody is lost on their first days on the job. Even the most senior programmer I know, who changed tons of jobs (because they weren't challenging enough) and was in charge of many developers in his own firm, said he always feels like an imposter on his first few days.
It's harder if it's your first programming job ever because you have no idea what to expect and you usually feel you don't know enough about this job.</p>
<p>That's why I compiled a list of tips, so it will be easier for you. Those tips are my personal opinion gathered by experience. They are suitable only for rookies - after you gain some experience, you'll make your own list.</p>
<h2 id="1-have-a-about-my-job-file">1. HAVE A 'ABOUT MY JOB FILE'</h2>
<p>There will be a lot of information in a very short time and there's a good chance you will forget at least some of those. </p>
<p>If you don't want to keep asking what are all the things, you need to do when starting a new project or where are all the images for the webpage, how to connect to FTP, or which user do you use for testing purposes on some login page, you should write them down.
And the thing you have always on your hand is your computer, so it's better to have a file than use a notebook.</p>
<p>+ that way, no one needs to know, you still don't remember something by heart.</p>
<h2 id="2-use-the-same-technologies-as-your-coworkers">2. USE THE SAME TECHNOLOGIES AS YOUR COWORKERS</h2>
<p>At home, I use Linux. To my surprise, when I started my first job, everybody there used Windows.
I haven't touched Windows for so long, I barely know how to change desktop background, so my new coworkers convinced me to use Linux. I am not a power user of it and when I was trying to set it up, I was lucky that my favorite coworker, who also used Linux, helped me and it seemed like a good decision at that time.</p>
<p>AND THAN, SHE QUIT!</p>
<p>And after she left, I had no one to ask - some things I learned to do on my own, but some things I never dared to touch. 
So, if you expect you're gonna need help with setting things up, use something that people around you will be able to help with.</p>
<h2 id="3-google-it-first">3. GOOGLE IT FIRST</h2>
<p>You're junior, you're working on projects you never saw before and you're not familiar with the workflow.
There is no shame in asking. </p>
<p>But, if you ask someone a question and they will google it and find the answer you
were looking for in the top 3 search results, they will think you're a lazy idiot. 
And if it will happen often, you will gain a bad reputation.</p>
<p>So, when you run into a problem:</p>
<ul>
<li>understand what it is</li>
<li>google it</li>
<li>try the solutions you find</li>
<li>go ask your mentor and you should form your question like this:
'I have this and this problem, I tried those and those solutions, I think it might be that, but I'm not sure how to fix it.'</li>
</ul>
<h2 id="4-do-something-obvious-first">4. DO SOMETHING OBVIOUS FIRST</h2>
<p>You are not yet familiar with the workflow, so you have a high chance you forgot something.
Either you didn't start the compiler for Less, you might be changing the wrong file, you forgot to import it...</p>
<p>I had many cases, that doing something obvious saved me time. Maybe something didn't have the correct height and I found that by applying 'border: 5px red solid'.
Maybe JS wasn't imported correctly or the JS for loop didn't have the correct condition. I found both problems by 'console.log(it's working!)'. In templates, I always first dump the data.</p>
<p>Once I was editing the wrong project (it was an old version of the same project, the new one had a different name) and it saved me a lot of time because I found it weird that I can't change the background color of the body.</p>
<h2 id="5-test-it">5. TEST IT</h2>
<p>If the project you're working on has tests, run them. 
If you did some front-end work, open it in more than one browser, and open your preferred mobile-simulator to see how it looks on different screens.
If you think your work might have an impact on other parts of the project, check that.</p>
<p>If your work is reliable and you catch most mistakes on your own, your coworkers, project managers, and bosses will trust you. 
And you get that by checking your work thoroughly.</p>
<h2 id="6-put-in-some-effort-with-your-coworkers">6. PUT IN SOME EFFORT WITH YOUR COWORKERS</h2>
<p>When I first started my job, all the girls at work were smokers. I'm not, but I went on
the smoke breaks with them anyway. 
And I got a crew; everyone knew that girls at that firm stick together.</p>
<p>BUT, because I had that girl's crew, I didn't connect with other (male) developers.
And one by one, girls left and there was no crew anymore. And I was left amidst the programmers, that had jokes of their own and I didn't fit in.</p>
<p>So, try to be friendly. You don't need to become their best friend, you don't need
to see them after work, but take a coffee break with them and if they order pizza once a week, join them, even if you're timid and don't like pizza (That's stupid, who doesn't like pizza :p)</p>
]]></content:encoded></item></channel></rss>