Quick Walkthrough Tutorial

This tutorial will take off where django official tutorial Writing your first Django app, part 4 left off. If you don’t have the project you can clone the following repository and checkout to completion of tutorial 04.

git clone https://github.com/monim67/django-polls
cd django-polls
git checkout d2.1t4

The Question model has a datetime field. We are going to create a page to add new poll questions and a page to edit them with a date-time-picker calendar on the datetime field. We are going to use Bootstrap 4 here, if you are using Bootstrap 3 just replace the 4’s with 3’s in the codes and instructions below. Install following packages:

pip install django-bootstrap4
pip install django-bootstrap-datepicker-plus

Add these packages to the list of INSTALLED_APPS as you did here on Tutorial 02.

# file: mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "bootstrap4",
    "bootstrap_datepicker_plus",
]

CreateView for Question model

Add a CreateView for Question model. The get_form method is used to specify widgets on the form fields.

# file: polls/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from bootstrap_datepicker_plus.widgets import DateTimePickerInput

from .models import Choice, Question


class CreateView(generic.edit.CreateView):
    model = Question
    fields = ['question_text', 'pub_date']
    def get_form(self):
        form = super().get_form()
        form.fields['pub_date'].widget = DateTimePickerInput()
        return form

# Leave other classes unchanged

Create a template named question_form.html in your app to render the form. If you use a different name you have to set template_name property of CreateView class in your views.py file above.

<!-- file: polls/templates/polls/question_form.html -->
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}

<form method="post">{% csrf_token %}
    {% bootstrap_form form %}
    <input type="submit" value="Save">
</form>

Add a get_absolute_url method to your Question model.

# file: polls/models.py
import datetime

from django.db import models
from django.urls import reverse
from django.utils import timezone


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def get_absolute_url(self):
        return reverse('polls:detail', kwargs={'pk': self.pk})

Add an urlpattern for creating new poll question.

# file: polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('create', views.CreateView.as_view(), name='create'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

Now run the developement server and visit http://localhost:8000/polls/create, if everything works fine you can wrap up your template in proper HTML.

<!-- file: polls/templates/polls/question_form.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    {% load bootstrap4 %}
    {% bootstrap_css %}
    {% bootstrap_javascript jquery='full' %}
    {{ form.media }}
</head>
<body>
    <div class="container">
        <div class="col-md-3">
        <form method="post">{% csrf_token %}
            {% bootstrap_form form %}
            {% buttons %}
            <button type="submit" class="btn btn-primary">Save</button>
            {% endbuttons %}
        </form>
        </div>
    </div>
</body>
</html>

UpdateView for Question model

We can now add a page to update a poll question. First we add an UpdateView to our views.

# file: add these to polls/views.py
class UpdateView(generic.edit.UpdateView):
    model = Question
    fields = ['question_text', 'pub_date']
    def get_form(self):
        form = super().get_form()
        form.fields['pub_date'].widget = DateTimePickerInput()
        return form

Then add a urlpattern to access the question update page.

# file: polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('create', views.CreateView.as_view(), name='create'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/update', views.UpdateView.as_view(), name='update'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

That’s it, run the developement server and visit http://localhost:8000/polls/1/update, if everything works fine you can checkout usage in custom form and model form in Usage page of the docs.