Django Models: Building a Blog

GOALS:

  • Introduce Django Models and Databases
  • Add a Blog to our Site
  • Use Python to analyze Blog Data

Starting the Blog

We will add a blog app to our site in the familiar manner. Be sure that you start by navigating to your project directory and activate the existing virtual environment (pipenv shell). Now, we create the new application with

python manage.py startapp blog

Next, be sure to add this app to your settings.py file in the main project directory.

Django Models

As we saw in our earlier applications, we had a default models.py file. The models are Django’s place to structure database elements. We will see how to use the admin console to produce entries to this database for our blog. For example, suppose we want to be able to parse Title, Author, Body, Created Date, and Published Date. We will create fields for these that are then stored as data in a default SQLite database.

To begin, open the models.py file. There are a variety of kinds of fields that we can use, but we will start with some basics. To see more refer to the Django Field documentation:

https://docs.djangoproject.com/en/2.0/ref/models/fields/#common-model-field-options

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.urls import reverse




# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length = 200)
    author = models.ForeignKey(User,on_delete = models.CASCADE, related_name = 'author')
    body = models.TextField()
    created_date = models.DateTimeField(blank = True, null = True)
    published_date = models.DateTimeField(blank=True, null=True)

This will allow us to login to the website and directly enter new blog posts with each of these fields. Notice that the title is a CharField whose length has been limited. The author is a ForeignKey that maps to user. This is a many to one element, that allows the user to create multiple posts. The body is a TextField and our created_date and published_date are DateTimeField types.

These will make more sense once we see the administration side which we will activate now.

Django Administration

The admin side of Django allows us to login to the site and work in a friendly browser view. We start with creating a login for the admin in the terminal with:

python manage.py createsuperuser

You will be promted to enter a username, email, and password. Remember these, as you will be using them in just a minute. Before being able to login, we register the model class we’ve created in our admin.py file as follows.

from django.contrib import admin
from .models import Post

admin.site.register(Post)

Now, run our server and head to 127.0.0.1:8000/admin. Hopefully after logging in, you will see the following:

Go ahead and add a few posts with arbitrary information such as:

Accessing our Data: QuerySets

Once you have a few data fields entered, you can go access this information in the shell. Shut your server down, and install IPython into your virtual enviornment. Next, start IPython up in the terminal running:

python manage.py shell

Now, we are using python just as we have in a Jupyter notebook. We want to load our model to examine, just as we’ve imported other objects in the past.

from blog.models import Post

Now we have access to all the attributes of the Post. Recall that when we defined the Post class, we gave it attributes named title, author, and body. We can display these looping through the Post objects.

for title in Post.objects.all():
    print title.title

Blog View

Much like we used the TemplateView for our earlier applications, we will use two additional view types that Django has for typical viewing behavior. First, is the ListView. This will connect with our data and allow us to list specific pieces of it. Makes sense for a blog homepage.

Create a new view, import the ListView, and a blank base.html and home.html file.

from django.views.generic import ListView

from . models import Post

class BlogListView(ListView):
    model = Post
    template_name = 'home.html'

Create the base much as our earlier example, but place the content inside of a <div> tag as follows:

<div class = "container">
    {% block content %}
    {% endblock content %}
</div>

The ListView contains an object_list that we can use to access the elements of the model in a view, similar to how we accessed them in the shell before. We will do this by looping through the blog entries and displaying the title and body of the entries.

{% block content %}
  {% for post in object_list %}
    <div class="post-entry">
      <h2><a href="">{{ post.title }}</a></h2>
      <p>{{ post.body }}</p>
    </div>
  {% endfor %}
{% endblock content %}

Finally, we create a url to our blog, add this to our navigation, and fire up the server. We should see something that looks like a list of our entries with the title and body of the post.

Adding Individual Blog Pages

While our blog pages now have a home, we would like to link to these pages and see the entire blog entry. To do so, we will create a template named blog_detail.html and use a DetailView to display the details of the blog content. We need three things here; a view for the detail pages, a template for them, and a url that maps to these.

The view for the individual blogs should feel familiar. We import the DetailView and create a class based view with the template named blog_detail.html.

class BlogDetailView(DetailView):
    model = Post
    template_name = 'blog_detail.html'

Next, we can create our template in the templates folder named blog_detail.html. We will ask for the detail object_list containing the model elements and return the title and body of the blog.

{% block content %}

    <div class="post-entry">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>

{% endblock content %}

Finally, we create the urls. We should recognize that now we are creating a list of urls, unlike our earlier work. We will make use of the fact that Django provides each entry in the database with an index called a primary key. In other words, my first blog post has primary key 1, my second 2, and so on. Thus, we can create urls based on these indicies as follows.

from django.urls import path, include

from . import views

urlpatterns = [
    path('blog/', views.BlogListView.as_view(), name = 'blog'),
    path('blog/<int:pk>/', views.BlogDetailView.as_view(),
         ]

In a similar manner, we can head over to our templates and attach href values to these titles based on the primary key as follows:

html <a href="{% url 'blog_detail' post.pk %}">Title</a>