-
Notifications
You must be signed in to change notification settings - Fork 57
Intro to Django Part 2
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
pip install django
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.
python manage.py startapp blog
This creates a ./blog/
folder containing app specific files.
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.
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',
]
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."
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.
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.
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
.
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 %}
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!
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/