API endpoint that enables a list of posts to be browsed including related models data and auxhiliary properties.

The configured endpoint purposefully does not permit a POST method as I do not want others creating new posts in the database.

GET /api/blog/posts/?format=api&offset=12
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 17,
    "next": "https://waynelambert.dev/api/blog/posts/?format=api&limit=3&offset=15",
    "previous": "https://waynelambert.dev/api/blog/posts/?format=api&limit=3&offset=9",
    "results": [
        {
            "id": 15,
            "title": "Implementing Selection Sort Algorithm in Python",
            "slug": "implementing-selection-sort-algorithm-python",
            "content": "<p>The selection sort algorithm approaches the problem of sorting data by dividing and conquering.</p>\r\n\r\n<p>The steps of the selection sort are as follows:</p>\r\n\r\n<p>Each cell of the array is checked from left to right to determine which has the smallest value. When moving from cell to cell, the lowest value&#39;s index that is found is stored in a tracking variable. If a cell contains a value that is even less than the one in the tracking variable, then the tracking variable becomes the new index number.</p>\r\n\r\n<p>The cell with the lowest index number is then switched with the cell where the iteration began for the passthrough in progress.</p>\r\n\r\n<p>This process continues for as many passthroughs as required to work through all of the indexed positions. This means that as the number of passthroughs increase within the process, the array gets shorter.</p>\r\n\r\n<p>First up, here is a Python implementation of selection sort.</p>\r\n\r\n<div contenteditable=\"false\" tabindex=\"-1\">\r\n<pre data-widget=\"codeSnippet\">\r\n<code class=\"language-python hljs\">&quot;&quot;&quot; The code is purposefully not written using Pythonic idioms &quot;&quot;&quot;\r\n\r\ndef selection_sort(array):\r\n    for i in range(0, len(array)):\r\n        min_index = i\r\n        for j in range(i + 1, len(array)):\r\n            if array[j] &lt; array[min_index]:\r\n                min_index = j\r\n        array[i], array[min_index] = array[min_index], array[i]\r\n    return array\r\n\r\n\r\nif __name__ == &#39;__main__&#39;:\r\n    random_array = [49, 81, 1, 9, 36, 64, 81, 100, 4, 16, 25]\r\n\r\n    sorted_list = selection_sort(random_array)\r\n    print(f&#39;The sorted list is {sorted_list}&#39;)</code></pre>\r\n</div>\r\n\r\n<p>Here is the same implementation in JavaScript</p>\r\n\r\n<div contenteditable=\"false\" tabindex=\"-1\">\r\n<pre data-widget=\"codeSnippet\">\r\n<code class=\"language-javascript hljs\">function selectionSort(array) {\r\n  for (let i = 0; i &lt; array.length; i++) {\r\n    var minIndex = i;\r\n    for (let j = i + 1; j &lt; array.length; j++) {\r\n      if(array[j] &lt; array[minIndex]) {\r\n        minIndex = j;\r\n      }\r\n    }\r\n    if (minIndex != i) {\r\n      let temp = array[i];\r\n      array[i] = array[minIndex];\r\n      array[minIndex] = temp;\r\n    }\r\n  }\r\n  return array;\r\n}\r\n\r\nrandomArray = [49, 81, 1, 9, 36, 64, 81, 100, 4, 16, 25]\r\n\r\nsortedList = selectionSort(randomArray);\r\nconsole.log(`The sorted list is ${sortedList}`);</code></pre>\r\n<img src=\"data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==\" /><span style=\"background-color:rgba(220,220,220,0.5)\"><img role=\"presentation\" src=\"data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==\" style=\"height:15px; width:15px\" title=\"Click and drag to move\" /></span></div>\r\n\r\n<p>For those mathematicians amongst you, you will notice that the sorted list produces the first 10 square numbers.</p>\r\n\r\n<pre>\r\n<code>The sorted list is [1, 4, 9, 16, 25, 25, 36, 49, 64, 81, 81, 100]</code></pre>\r\n\r\n<p>The selection sort algorithm has a time complexity (or Big-O notation) of O(n&sup2;)</p>",
            "reference_url": "",
            "publish_date": "2019-09-05T19:39:08.573816Z",
            "updated_date": "2020-01-29T12:56:24.364618Z",
            "image": "https://wl-portfolio.s3.amazonaws.com/post_images/algorithm7.jpg",
            "status": "Publish",
            "word_count": 381,
            "reading_time": 6,
            "post_absolute_url": "/blog/post/implementing-selection-sort-algorithm-python/",
            "author_username": "wayne-lambert",
            "author_first_name": "Wayne",
            "author_last_name": "Lambert",
            "author_full_name": "Wayne Lambert",
            "author_initials": "WL",
            "author_display_name": "Wayne Lambert",
            "author_join_year": 2019,
            "author_view": 1,
            "author_created_date": "2019-07-21T10:02:09.888000Z",
            "author_updated_date": "2022-12-14T14:44:36.068604Z",
            "author_absolute_url": "/blog/users/wayne-lambert/profile/",
            "author_profile_picture": "https://wl-portfolio.s3.amazonaws.com/profile_pics/gravatar-500.jpg",
            "categories": [
                {
                    "id": 8,
                    "name": "Algorithms",
                    "slug": "algorithms",
                    "created_date": "2019-09-05T08:51:56.026246Z"
                },
                {
                    "id": 10,
                    "name": "Data Structures",
                    "slug": "data-structures",
                    "created_date": "2019-09-26T20:04:59.582866Z"
                },
                {
                    "id": 4,
                    "name": "JavaScript",
                    "slug": "javascript",
                    "created_date": "2019-07-27T21:39:47.440429Z"
                },
                {
                    "id": 9,
                    "name": "Python",
                    "slug": "python",
                    "created_date": "2019-09-05T09:25:47.465274Z"
                }
            ]
        },
        {
            "id": 3,
            "title": "Developing Django Project with Docker: The Dockerfile",
            "slug": "developing-django-project-docker",
            "content": "<p>Docker is a headache to learn but once you get the hang of it and understand all of its concepts and moving pieces, then it works extremely well. I say &#39;all&#39; loosely here of course, since you can get 95% of what you will ever need by learning maybe 10% of its featureset.</p>\r\n\r\n<p>I can see that using Docker would give even more benefits when developing a project with multiple languages and frameworks such as having a React front-end with your Django application. This would mean that the packaging requirements usually managed with the <em>package.json </em>file could also be managed with Docker.</p>\r\n\r\n<p>During my time learning about Docker and the development setup and especially making it play nicely with pipenv, I learned that the configuration is very picky. I spent countless hours researching, configuring, building, testing and above all, learning!</p>\r\n\r\n<p>Anyway, let me guide you through the <strong>Dockerfile</strong><em> </em>that I am using as at the time of writing this guide.</p>\r\n\r\n<p><strong>Dockerfile: In Full</strong></p>\r\n\r\n<pre>\r\n<code># Official Python runtime as the base image\r\nFROM python:3.7.3-alpine\r\n\r\nRUN apk --update add \\\r\n    build-base \\\r\n    postgresql \\\r\n    postgresql-dev \\\r\n    libpq \\\r\n    gettext \\\r\n    nginx \\\r\n    # Pillow dependencies\r\n    jpeg-dev \\\r\n    zlib-dev\r\n\r\n# Set working directory\r\nWORKDIR /code\r\n\r\n# Add metadata to the image\r\nLABEL author=\"Wayne Lambert &lt;[email protected]&gt;\" \\\r\n    version=\"2019.07\" \\\r\n    description=\"Docker image for portfolio site. Hosted at https://waynelambert.dev\"\r\n\r\n# Install pipenv from PyPI\r\nRUN pip install pipenv\r\n\r\n# Copy local files to container\r\nCOPY Pipfile Pipfile.lock /code/\r\n\r\n# Install project dependencies using exact versions in Pipfile.lock\r\nRUN pipenv install --system --ignore-pipfile --deploy --dev\r\n\r\n# Copy the contents of code folder locally to the code directory in container\r\nCOPY . .\r\n\r\n# Run script file.\r\nCMD ./run-dev.sh</code></pre>\r\n\r\n<p>Let&#39;s walk through what is declared within the Dockerfile above step-by-step...</p>\r\n\r\n<pre>\r\n<code># Official Python runtime as the base image\r\nFROM python:3.7.3-alpine</code></pre>\r\n\r\n<p>This line pulls down a streamlined version of Python specifically suitable for the Alpine Linux distribution. This acts as the basis for the remainder of the docker build process.</p>\r\n\r\n<pre>\r\n<code>RUN apk --update add \\\r\n    build-base \\\r\n    postgresql \\\r\n    postgresql-dev \\\r\n    libpq \\\r\n    gettext \\\r\n    nginx \\\r\n    # Pillow dependencies\r\n    jpeg-dev \\\r\n    zlib-dev</code></pre>\r\n\r\n<p>This step adds or updates some dependency packages that are required for my project. <strong>apk</strong> is Alpine&#39;s package manager command in a similar way to Ubuntu&#39;s <strong>apt</strong> command.</p>\r\n\r\n<ul>\r\n\t<li><strong>Postgresql</strong> is for the project&#39;s database</li>\r\n\t<li><strong>nginx</strong> is for the web server that would be used in development. It is not really required for the development build.</li>\r\n\t<li>The <strong>Pillow</strong> dependencies are for image management within the project.</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<pre>\r\n<code># Set working directory\r\nWORKDIR /code</code></pre>\r\n\r\n<p>This sets the work directory to a folder location within the container being created called <strong>/code</strong>. I have found that it is useful to have this a slightly different than you local development environment. In my local development environment, I tend to call the source folder of the project <strong>src</strong>. It should also be noted that if the directory does not exist within the container then setting the <strong>WORKDIR</strong> in the build makes the directory.</p>\r\n\r\n<pre>\r\n<code class=\"language-bash\">RUN mkdir code</code></pre>\r\n\r\n<p>There is no need to place a line like this before it.</p>\r\n\r\n<pre>\r\n<code># Add metadata to the image\r\nLABEL author=\"Wayne Lambert &lt;[email protected]&gt;\" \\\r\n    version=\"2019.07\" \\\r\n    description=\"Docker image for portfolio site. Hosted at https://waynelambert.dev\"</code></pre>\r\n\r\n<p>This just adds some metadata to the image that you&#39;re creating which might be useful when you put the image onto Docker Hub later.</p>\r\n\r\n<pre>\r\n<code># Install pipenv from PyPI\r\nRUN pip install pipenv</code></pre>\r\n\r\n<p>Prior to this line being executed with the build script, pipenv does not exist within the container&#39;s installation of Python which was pulled as the base image from Docker Hub at the start of the build.</p>\r\n\r\n<pre>\r\n<code># Copy local files to container\r\nCOPY Pipfile Pipfile.lock /code/</code></pre>\r\n\r\n<p>The Pipfile and Pipfile.lock only exist locally within your project&#39;s root directory. These files need to exist within the container&#39;s working directory, so that they can be used by the container&#39;s recently downloaded pipenv package to install the remainder of your project&#39;s dependencies.</p>\r\n\r\n<pre>\r\n<code># Install project dependencies using exact versions in Pipfile.lock\r\nRUN pipenv install --system --ignore-pipfile --deploy --dev</code></pre>\r\n\r\n<p>This command uses pipenv to run a system installation using Python&#39;s default pip package manager to install of the project&#39;s dependencies including those that are labelled as <em>&#39;dev-packages&#39;</em> within the <strong>Pipfile</strong>. If you omit the <strong>--dev</strong> flag, then the command will only install those required for production.</p>\r\n\r\n<p>The <strong>--ignore-pipfile</strong> flag means that the packages are installed as per the strict version numbers specified in the <em>&#39;Pipfile.lock&#39;</em></p>\r\n\r\n<p>The <strong>--deploy</strong> flag ensures that your <strong>Pipfile.lock</strong> file is up to date.</p>\r\n\r\n<pre>\r\n<code># Copy the contents of code folder locally to the code directory in container\r\nCOPY . .</code></pre>\r\n\r\n<p>This copies all the folders and files within your local development environments source folder (in this example, <strong>src</strong><em> </em>folder) into your working directory folder within your Docker container (in this example, the folder we called <strong>/code</strong>.</p>\r\n\r\n<pre>\r\n<code># Run script file.\r\nCMD ./run-dev.sh</code></pre>\r\n\r\n<p>... and finally, this file runs a shell script that is now accessible from within the container&#39;s working directory. The contents of the shell script is below.</p>\r\n\r\n<pre>\r\n<code>#!/bin/bash\r\n\r\npython manage.py migrate\r\n\r\npython manage.py runserver 0.0.0.0:8001</code></pre>\r\n\r\n<p>This script is being run from within the container and therefore does not need to be preceeded with docker exec...</p>\r\n\r\n<p>The first command migrates the history of your migration files from within your project. You will need to make sure that these migrations are all sound.</p>\r\n\r\n<p>The second command spins up a webserver that is accessible from your browser by going to either 127.0.0.1/8001 or localhost:8001</p>\r\n\r\n<p>Since the <strong>docker-compose.yml</strong> file invokes the build process listed within the <strong>Dockerfile</strong>,<em> </em>there is a mapping that maps the ports on the Django project&#39;s service (often called <em>&#39;web&#39;</em>) from port 8000 to 8001. Django&#39;s development port is port 8000 and I have chosen to map it to port 8001 within the container. I have found this another useful indicator that you are browsing your project through a Docker container rather than Django&#39;s standard development server.</p>\r\n\r\n<p>The Dockerfile on GitHub for this particular post is <a href=\"https://github.com/WayneLambert/portfolio/blob/6594d30dde032f259235aa99d71258d675ca2f0e/Dockerfile\">here</a>. The link below is where the project&#39;s most-up-date version is in case I find further enhancements to the build process.</p>",
            "reference_url": "https://github.com/WayneLambert/portfolio/blob/master/docker-compose.yml",
            "publish_date": "2019-07-21T10:02:09.888000Z",
            "updated_date": "2019-09-06T14:04:04.275447Z",
            "image": "https://wl-portfolio.s3.amazonaws.com/post_images/django-docker.jpg",
            "status": "Publish",
            "word_count": 1034,
            "reading_time": 14,
            "post_absolute_url": "/blog/post/developing-django-project-docker/",
            "author_username": "wayne-lambert",
            "author_first_name": "Wayne",
            "author_last_name": "Lambert",
            "author_full_name": "Wayne Lambert",
            "author_initials": "WL",
            "author_display_name": "Wayne Lambert",
            "author_join_year": 2019,
            "author_view": 1,
            "author_created_date": "2019-07-21T10:02:09.888000Z",
            "author_updated_date": "2022-12-14T14:44:36.068604Z",
            "author_absolute_url": "/blog/users/wayne-lambert/profile/",
            "author_profile_picture": "https://wl-portfolio.s3.amazonaws.com/profile_pics/gravatar-500.jpg",
            "categories": [
                {
                    "id": 5,
                    "name": "Docker",
                    "slug": "docker",
                    "created_date": "2019-07-27T21:39:51.584456Z"
                }
            ]
        },
        {
            "id": 9,
            "title": "How to Add a Sitemap to Your Django Site",
            "slug": "add-sitemap-django-site",
            "content": "<p>If you would like to add a sitemap to your project so that Google can easily crawl and index the content of your website for SEO purposes, then this can be achieved using the following steps.</p>\r\n\r\n<p>Add the sitemaps to the list of installed apps. It makes sense for this to be added at the bottom of the pre-installed apps that come as part of a standard &#39;<strong>django-admin startproject &lt;my_project_name&gt; .</strong>&#39; setup. This should be before any third party or project apps.</p>\r\n\r\n<pre>\r\n<code class=\"language-python\"># Settings.py\r\n\r\nINSTALLED_APPS = [\r\n    ...\r\n    'django.contrib.sitemaps',  # Add\r\n    ...\r\n]</code></pre>\r\n\r\n<p>Next up, let&#39;s create the sitemap within the app that you would like to create the sitemap for. In my case, I have a <strong>Category</strong> and a <strong>Post</strong> model within my <strong>blog</strong> app.</p>\r\n\r\n<pre>\r\n<code class=\"language-python\"># blog/sitemap.py\r\n\r\nfrom django.contrib.sitemaps import Sitemap\r\nfrom django.urls import reverse\r\nfrom blog.models import Category, Post\r\n\r\n\r\nclass CategorySitemap(Sitemap):\r\n    changefreq = 'daily'\r\n    priority = 0.5\r\n\r\n    def items(self):\r\n        return Category.objects.all()\r\n\r\n\r\nclass PostSitemap(Sitemap):\r\n    changefreq = 'daily'\r\n    priority = 0.5\r\n\r\n    def items(self):\r\n        return Post.objects.filter(status=1).order_by('-publish_date')\r\n\r\n    def lastmod(self, obj):\r\n        return obj.updated_date\r\n</code></pre>\r\n\r\n<p>Finally, we will just need to wire this up within the <u>project&#39;s</u> <strong>urls.py</strong> file. My project is called &#39;<strong>ab_back_end</strong>&#39;.</p>\r\n\r\n<pre>\r\n<code class=\"language-python\"># ab_back_end/urls.py\r\n\r\n...\r\nfrom django.contrib.sitemaps.views import sitemap\r\nfrom blog.sitemap import CategorySitemap, PostSitemap\r\n...\r\n\r\nurlpatterns = [\r\n    ...  # Block of your project's urls\r\n]\r\n\r\n\r\n# Represents the sitemaps that you previously created within sitemaps.py\r\nsitemaps = {\r\n    'categories': CategorySitemap,\r\n    'posts': PostSitemap,\r\n}\r\n\r\n# Append the sitemaps to your urlpatterns list.\r\nurlpatterns += [\r\n    path('sitemap.xml', sitemap, {'sitemaps': sitemaps},\r\n         name='django.contrib.sitemaps.views.sitemap'),\r\n]\r\n</code></pre>\r\n\r\n<p>That&#39;s it! You should now be able to access your site at <strong>/sitemap.xml</strong></p>",
            "reference_url": "",
            "publish_date": "2019-08-02T12:31:44.451555Z",
            "updated_date": "2019-08-04T22:33:05.341406Z",
            "image": "https://wl-portfolio.s3.amazonaws.com/post_images/django-sitemap.png",
            "status": "Publish",
            "word_count": 269,
            "reading_time": 4,
            "post_absolute_url": "/blog/post/add-sitemap-django-site/",
            "author_username": "wayne-lambert",
            "author_first_name": "Wayne",
            "author_last_name": "Lambert",
            "author_full_name": "Wayne Lambert",
            "author_initials": "WL",
            "author_display_name": "Wayne Lambert",
            "author_join_year": 2019,
            "author_view": 1,
            "author_created_date": "2019-07-21T10:02:09.888000Z",
            "author_updated_date": "2022-12-14T14:44:36.068604Z",
            "author_absolute_url": "/blog/users/wayne-lambert/profile/",
            "author_profile_picture": "https://wl-portfolio.s3.amazonaws.com/profile_pics/gravatar-500.jpg",
            "categories": [
                {
                    "id": 1,
                    "name": "Django",
                    "slug": "django",
                    "created_date": "2019-07-27T21:39:31.016414Z"
                }
            ]
        }
    ]
}