Skip to content

Intro to Django Part 2

christine edited this page Feb 21, 2017 · 10 revisions

Learning by Doing

In order to get familiar with the fundamentals of Django, let's practice making a Django project from scratch. To start, let's create a new folder in your project directory:

mkdir fec-example
cd fec-example

Activate your virtual environment.

There are multiple ways to accomplish this, so please feel free to use whatever works for you. If you're unsure, here is one example that you can follow to create one and then activate it:

pyvenv .venv
. .venv/bin/activate

Once your virtual environment is activated, check your Python version to make sure it is 3.4+:

python -V

Install Django

pip install django

Start a New Project

With Django installed, let's a start a new project:

django-admin startproject fec .

The startproject command creates a ./fec/ folder that contains starting project files.

Note: Project names have to be a character only string, no dashes or underscores allowed.

Create An App

python manage.py startapp blog

This creates a ./blog/ folder containing app specific files.

Init Database

For this example project, we can just use a flat sqlite database for simplicity. To initialize the database:

python manage.py migrate

This will create a db.sqlite3 where our data will be stored.

Setup First App

In ./fec/settings.py, add the blog to the list of installed apps:

INSTALLED_APPS = [
    'blog.apps.BlogConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Setup Model

For our blog app example, let's define a model in ./fec/blog/models.py:

from django.db import models
from django.contrib import admin
from datetime import datetime

class BlogEntry(models.Model):
    title = models.CharField(max_length=200, blank=False)
    entry = models.TextField(blank=False)
    slug = models.SlugField(blank=False)
    published_date = models.DateTimeField('date published', default=datetime.now)

    class Meta:
        verbose_name_plural = "Blog Entries"

class BlogEntryAdmin(admin.ModelAdmin):
    list_display = ('title', 'published_date')

admin.site.register(BlogEntry, BlogEntryAdmin)

Setting a required title, entry, slug, and date. At the same time we are setting fields for the Django admin site, including a verbose pluralization of "BlogEntry" so it doesn't show up as default "BlogEntrys."

Make Migrations

Every time we add, change, or delete fields in the models.py file, we need to make a migration file in order to instruct changes to the database.

python manage.py makemigrations

After running this, we should get this output from the terminal:

Migrations for 'blog':
  blog/migrations/0001_initial.py:
    - Create model BlogEntry

This means the model migrations were successful. To actually enact change in our database, we must next run:

python manage.py migrate

To which we should get this output:

Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying blog.0001_initial... OK

It ran the migration successfully and now our database schema is updated.

Setup Django Admin

Create an admin user/password to log into the admin site:

python manage.py createsuperuser

Then run the development server:

python manage.py runserver

And login at http://127.0.0.1:8000/admin/
Now we can add some blog entries into the database directly through the Django admin site.

Writing Our First View

Once we have some blog entries in the database, let's write a view so we can see our blog entries. In ./fec/blog/views.py:

from django.shortcuts import render

from blog.models import BlogEntry


def index(request):
    entries = BlogEntry.objects.order_by('-published_date')[:5]
    context = {'entries': entries}

    return render(request, 'index.html', context)

This view will grab the latest 5 blog entries from the database using a Django queryset (https://docs.djangoproject.com/en/1.10/ref/models/querysets/), and render it through index.html.

Writing Templates

Now to actually see the view in action, let's make templates.
In /blog/templates/base.html:

<!DOCTYPE html>
<html>
<head>
  <title>FEC Sample Blog - {% block title %}{% endblock title %}</title>
</head>
<body>

  <h1>FEC Sample Blog</h1>

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

</body>
</html>

This is a base template file in which other templates can inherit from.
We can then extend from this template, with /blog/templates/index.html:

{% extends "base.html" %}

{% block title %}Blog Entries{% endblock title %}

{% block content %}

  {% for entry in entries %}
    <article class="entry">
      <h2>{{ entry.title }}</h2>
      <div class="date">{{ entry.published_date }}</div>
      <p>{{ entry.entry }}</p>
    </article>
  {% endfor %}

{% endblock content %}

Set URLs

Now to finally see our blog index page, we have to hook up a url pattern to the view:

from django.conf.urls import url
from django.contrib import admin

from blog import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^admin/', admin.site.urls),
]

The first line in urlpatterns is a regex pattern that will match the root URL to the blog index view. So going to 127.0.0.1:8000 will result in seeing our blog index page!

Set another View and URL

Let's add a view to see individual blog entries. In /blog/views.py, add:

def entry(request, slug):
    entry = BlogEntry.objects.get(slug=slug)

    context = {'entry': entry}

    return render(request, 'entry.html', context)

Make our template entry.html:

{% extends "base.html" %}

{% block title %}{{ entry.title }}{% endblock title %}

{% block content %}

  <article class="entry">
    <h2>{{ entry.title }}</h2>
    <div class="date">{{ entry.published_date }}</div>
    <p>{{ entry.entry }}</p>
  </article>

{% endblock content %}

And in ./fec/urls.py add a line in urlpatterns:

    url(r'^(?P<slug>[\w-]+)$', views.entry),

That pattern will catch a string of characters and pass it as slug to the entry view.
Then we can modify /blog/templates/index.html with this line:

<h2><a href="/{{ entry.slug }}">{{ entry.title }}</a></h2>

And now we can link out to individual blog entry pages. With that, we now have a very basic working blog powered by Django! To continue on expanding your project, you can read up on the Django documentation: https://docs.djangoproject.com/en/1.10/