How to display Dev To posts on your website blog using Dev To API and Django.
Published: 2021-03-01 21:06:00

Let's assume you own a website or you want to build one and you want to add a blog to it. So you go to Google and google **"_How to add a blog to your website_."** After going through the results, you can't find a better option that enables you to add a blog to your site for free or without using WordPress. 

A few weeks ago I found myself in this situation and as I went on doing my research, I discovered that you can use dev to API to display articles published there on your website without someone getting redirected to Dev To when they want to read the articles.

My website uses Django for the backend and for that reason, I googled **"_how to display dev to posts on your website using Django_."** I went through the results returned by the search but none gave me a solution to the problem I wanted to solve.

After days of trial and error trying to figure out how to do that, I was able to display dev to posts on my website.

Here is how I did it.

##Set Up

First things first, make sure you have python installed in your system.

###Installing Django

To install Django we will use `Pipenv` which is used to manage virtual environments. You can install Pipenv to your system using [this guide.](https://pipenv-fork.readthedocs.io/en/latest/install.html)

Let’s create a new directory and install Django. First, navigate to the Desktop, create a new directory `Articles`, and enter it with `cd`.

```python
$ cd ~/Desktop
$ mkdir Articles
$ cd Articles
```

Now use Pipenv to install Django.

```python
$ pipenv install django
```
Then create a virtual environment using `pipenv shell`

```python
$ pipenv shell
```

You should now see parentheses around the name of your current directory on your command line which indicates the virtual environment is activated.

```python
(Articles) $
```

Create a new Django project called `Blog` with the following command. Don’t forget that period . at the end.

```python
(Articles) $ django-admin startproject Blog .
```

Run the command below and then visit [http://127.0.0.1:8000/](http://127.0.0.1:8000/). You should see Django welcome page.

```python
(Articles) $ python manage.py runserver
```

Now it’s time to create our Django app. From the command line, quit the server with `Control+c`. Then use the `startapp` command followed by the name of our app, which will be `posts`.

```python
(Articles) $ python manage.py startapp posts
```

Open the `settings.py` file and scroll down to `INSTALLED_APPS` where you’ll see six built-in Django apps already there. Add our new `posts` app at the bottom:

```python
# Blog/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'posts', # new
]
```

###Models, Views, URLs, Templates

####1. Models
First, we will create a model for our project so that we can store the articles fetched by the Dev To API into a database.

Models.py

```python
from django.db import models
import datetime

class Article(models.Model):
    title = models.TextField(blank=True)
    description = models.TextField(blank=True)
    cover_image = models.TextField(blank=True)
    article_body = models.TextField(blank=True)
    published_at = models.DateTimeField(default=datetime.date.today, blank=True, null=True)

    def __str__(self):
        return self.title
```  

Run migrations with the commands below

```python
(Articles) $ python manage.py makemigrations

(Articles) $ python manage.py migrate

```

To register our model, open `admin.py` and it should look like this.

Admin.py

```python
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import Article

class ArticleAdmin(admin.ModelAdmin):
    list_display = ('id', 'title')
    

admin.site.register(Article, ArticleAdmin)
```

Then create a superuser in order to be able to login to the admin and view data stored in our database.

```python
(Articles) $ python manage.py createsuperuser
```

####2. views
Since we will be making requests to Dev To API, we will need to install `requests` python library.

```python
$ pipenv install requests
```

Now visit dev to [API website](https://docs.forem.com/api/) and read about **_getting an API key_** together with various API endpoints. 

Once on the website, scroll down and on your bottom left select `authentification` to learn how to get an `API key`.

Then below `authentification`, select `articles`. Scroll down the drop-down menu and select `User's published articles`.

On your right, you can now see `Request samples`.

Now this is how your `views.py` file should look like.

views.py

```python
from django.shortcuts import render
import requests
from .models import Article

def get_articles(request):
   all_articles = {}

   API_KEY = 'Your_API_KEY'
    
   url = 'https://dev.to/api/articles/me/published'

   headers = {'api-key': API_KEY}
   
   response = requests.get(url, headers=headers)
   
   data = response.json()

   for i, item in enumerate (data):
      article_data = Article(
         title = data[i]['title'],
         description = data[i]['description'],
         cover_image = data[i]['cover_image'],
         article_body = data[i]['body_markdown'],
         published_at = data[i]['published_at']
      )
   
      article_data.save()

      all_articles = Article.objects.all().order_by('-published_at').distinct('published_at')

      return render (request, "blog.html", {"all_articles": all_articles})
```

In order to display `Article Body`, we will need to create another `view`. In this `view`, we are querying article by `id`.

```python
def blogBody(request, id):
   article = Article.objects.get(id = id)

   return render (request, "blogBody.html", {"article": article})
```

Your `views.py` file should now look like this.

```python
from django.shortcuts import render
import requests
from .models import Article

def get_articles(request):
   all_articles = {}

   API_KEY = 'Your_API_KEY'
    
   url = 'https://dev.to/api/articles/me/published'

   headers = {'api-key': API_KEY}
   
   response = requests.get(url, headers=headers)
   
   data = response.json()

   for i, item in enumerate (data):
      article_data = Article(
         title = data[i]['title'],
         description = data[i]['description'],
         cover_image = data[i]['cover_image'],
         article_body = data[i]['body_markdown'],
         published_at = data[i]['published_at']
      )
   
      article_data.save()

      all_articles = Article.objects.all().order_by('-published_at').distinct('published_at')

      return render (request, "blog.html", {"all_articles": all_articles})

def blogBody(request, id):
   article = Article.objects.get(id = id)

   return render (request, "blogBody.html", {"article": article})
```

####3. URLs

Now we need to configure our `urls`. Within the `posts app`, create a new `urls.py` file.

urls.py

```python
from django.urls import path
from .views import get_articles, blogBody


urlpatterns = [
    path("blog", blog, name="blog"),
    path("article/<int:id>", blogBody, name="article"),
]
```

The last step is to update our `Blog/urls.py` file. It’s common to have multiple apps within a single Django project, like pages here, and they each need their own dedicated URL path.

Update the existing `Blog/urls.py` file as follows:

```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("", include("posts.urls"))
]
```

####4. Templates

Create a directory called `templates` and an HTML file called `blog.html` and `blogBody.html`.

```python
(Articles) $ mkdir templates
(Articles) $ touch templates/blog.html
(Articles) $ touch templates/blogBody.html
```

Next, we need to update `Blog/settings.py` to tell Django the location of our new templates directory. This is a one-line change to the setting `'DIRS'` under `TEMPLATES`.

```python
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')], #new
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
```

Our `blog.html` file should now look like this:

```html
{% for article in get_articles %}
<img src="{{article.cover_image}}" alt="">
<h4>{{article.title}}</h4>
<p>{{article.description}}</p>
<a href="{% url 'article' article.id %}">Read More...</a>
{% endfor %}
```

####Article Body

When we make the `API` call, the article body is fetched as `article markdown`. The markdown is received from the API as a string. This means it will look like the raw content you enter on DEV To, rather than the preview/published version (i.e. with all the markdown syntax like ## for headings).

To display it on your website as it appears on DEV To, you'll need to add an extra step to turn the string markdown into HTML. There are a lot of markdown parsing libraries that can do this for you but in this project, we will use a markdown parsing library for Django called `Markdown`.

To use `Markdown` we will need to install it into our project.

```python
$ pipenv install markdown
```

We will create a custom template filter that uses `Markdown`. Create a `templatetags` directory within our posts app and then a `markdown_extras.py` file.

```python
(Articles) $ mkdir posts/templatetags
(Articles) $ touch posts/templatetags/markdown_extras.py
```

The file itself will import the `markdown` package and use the fenced code block extension.

```python
# posts/templatetags/markdown_extras.py
from django import template
from django.template.defaultfilters import stringfilter

import markdown as md

register = template.Library()


@register.filter()
@stringfilter
def markdown(value):
    return md.markdown(value, extensions=['markdown.extensions.fenced_code'])
```

Now we load the custom filter into our template so that content written in Markdown will be outputted as HTML.

Our `blogBody.html` file should now look like this:

```html
{% load markdown_extras %}

<h4>{{article.title}}</h4>
<img src="{{article.cover_image}}" alt="">
<span>{{article.published_at }}</span>
<p>{{article.article_body | markdown | safe}}</p>
```
##Conclusion

Articles should now appear on your website just like they appear on Dev To.

Hope you find this article helpful. All the best in your coding.