Django is a versatile, extremely fast, very secure, and easily scalable Python Web framework, with many extra feature right out of the box, like: user authentication, content administration, etc.

Requirements

$ sudo apt-get install git
$ sudo apt-get install python3
$ sudo apt-get install python3-pip
$ sudo pip install virtualenv

Environment

$ mkdir project
$ cd project
$ virtualenv --python=/usr/bin/python3 env

You can activate it.

$ source ./env/bin/activate

Verify the version of python from the first line by the below command.

$ python
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

When not using you can deactivate it.

$ deactivate

Django project

$ pip install django
$ python -m django --version

Django Installation

$ pip freeze > requirements.txt
$ pip install -r requirements.txt
$ django-admin startproject website
$ cd website
$ python manage.py migrate
$ python manage.py runserver

Django Project initial structure

$ python manage.py runserver 0:8000

Then go to http://localhost:8000.

Django Running migrations

Git

Let’s use git to save the current changes.

$ vim .gitignore
*.pyc
*.swp
env
db.sqlite3
$ git init
$ git add .
$ git commit -am "Initial commit"

Django Blog app

Now let’s add a blog.

$ python manage.py startapp blog
$ python manage.py makemigrations blog
$ python manage.py migrate
$ python manage.py shell
$ python manage.py createsuperuser

Project URLS

$ vim website/urls.py
from django.conf.urls import include, url
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^', include('blog.urls')),
]

Project settings

$ vim website/settings.py
# Application definition

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

App URLS

$ vim blog/urls.py
from django.conf.urls import url
from blog import views


urlpatterns = [
    url(r'^blog/(?P<pk>[0-9]+)/$', views.ShowView.as_view(), name='post-show'),
    url(r'^$', views.IndexView.as_view(), name='blog'),
]

App views

$ vim blog/views.py
from django.views import generic
from django.shortcuts import get_object_or_404
from blog.models import Post


class IndexView(generic.ListView):
    model = Post
    template_name = "index.html"
    context_object_name = "posts"
    queryset = Post.objects.all()


class ShowView(generic.DetailView):
    model = Post
    template_name = "show.html"
    context_object_name = "post"

    def get_object(self, queryset=None):
        pk = self.kwargs.get(self.pk_url_kwarg, None)
        return get_object_or_404(Post, pk=pk)

App models

$ vim blog/models.py
from django.db import models
from django.urls import reverse


class Post(models.Model):
    title = models.CharField(max_length=150)
    author = models.CharField(max_length=150)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    modified_at = models.DateTimeField(auto_now=True, editable=False)

    def get_absolute_url(self):
        return reverse('post-show', args=[str(self.id)])

App templates

$ mkdir blog/templates
$ vim blog/templates/base.html
<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
        <title>Blog</title>
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>
$ vim blog/templates/index.html
{% extends 'base.html' %}
{% block content %}
  <h1>Blog posts</h1>
  {% for post in posts %}
    <div><a href="{{ post.get_absolute_url }}">{{ post.title }}</a> by {{ post.author }}</div>
  {% endfor %}
{% endblock %}
$ vim blog/templates/show.html
{% extends 'base.html' %}
{% block content %}
        <h1>{{ post.title }}</h1>
        <h2>by {{ post.author }}</h2>
        <div>{{ post.content }}</div>
        <a href="/">Back</a>
{% endblock %}

Final steps

$ python manage.py migrate
$ python manage.py runserver

Django New model migration

Then go to http://localhost:8000.

$ vim blog/admin.py
from django.contrib import admin
from .models import Post


@admin.register(Post)
class BlogAdmin(admin.ModelAdmin):
    pass

Django Admin with new Post model

$ git commit -am "Add blog"

And that’s all! Check out the Django documentation for more.