---
tags: Python Web
source: Django 2.0 для начинающих, Глава 10, с.210
---
# Тема 8. Bootstrap
https://github.com/roman-yatsenko/django-topics/tree/main/news
## Приложение Pages
```shell
python manage.py startapp pages
```
### `news_project\settings.py`
```python=33
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
'pages' # new
]
```
### `news_project\urls.py`
```python=16
from django.contrib import admin
from django.urls import path, include # delete next import
urlpatterns = [
path('', include('pages.urls')), # change
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
]
```
```shell
touch pages/urls.py
```
### `pages\urls.py`
```python=
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomePageView.as_view(), name='home'),
]
```
### `pages\views.py`
```python=
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'home.html'
```
```shell
python manage.py runserver
```
## Тесты
### `pages\tests.py`
```python=
from django.contrib.auth import get_user_model
from django.test import SimpleTestCase, TestCase
from django.urls import reverse
class HomePageTests(SimpleTestCase):
def test_home_page_status_code(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
def test_view_url_by_name(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'home.html')
class SignupPageTests(TestCase):
username = 'newuser'
email = 'newuser@email.com'
def test_signup_page_status_code(self):
response = self.client.get('/users/signup/')
self.assertEqual(response.status_code, 200)
def test_view_url_by_name(self):
response = self.client.get(reverse('signup'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('signup'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'signup.html')
def test_signup_form(self):
new_user = get_user_model().objects.create_user(self.username, self.email)
self.assertEqual(get_user_model().objects.all().count(), 1)
self.assertEqual(get_user_model().objects.all()[0].username, self.username)
self.assertEqual(get_user_model().objects.all()[0].email, self.email)
```
```shell
python manage.py test
```
## Bootstrap
https://getbootstrap.com/docs/4.6/getting-started/introduction/
### `templates\base.html`
```htmlmixed=
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<title>Newspaper App</title>
</head>
<body>
{% block content %}
{% endblock %}
<!-- Optional JavaScript; choose one of the two! -->
<!-- Option 1: jQuery and Bootstrap Bundle (includes Popper) -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
</body>
</html>
```
```shell=
python manage.py runserver
```
## NavBar
https://getbootstrap.com/docs/4.6/components/navbar/#supported-content
### `templates\base.html`
```htmlmixed=13
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
<a class="navbar-brand" href="{% url 'home' %}">Newspaper</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
{% if user.is_authenticated%}
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ user.username }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{% url 'password_change' %}">Change password</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
</div>
</li>
</ul>
{% else %}
<form class="form-inline ml-auto">
<a class="btn btn-outline-secondary" href="{% url 'login' %}">Log in</a>
<a class="btn btn-primary ml-2" href="{% url 'signup' %}">Sign Up</a>
</form>
{% endif %}
</div>
</nav>
<div class="container">
{% block content %}
{% endblock %}
</div>
```
### `templates\registration\login.html`
```htmlmixed=10
<button class="btn btn-success ml-2" type="submit">Login</button>
```
## Signup Form
```shell
pipenv install django-crispy-forms
```
### `news_project\settings.py`
```python=33
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 3rd Party
'crispy_forms',
# Local
'users',
'pages',
]
```
```python=135
CRISPY_TEMPLATE_PACK = 'bootstrap4'
```
### `templates\signup.html`
```htmlmixed=
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Sign Up{% endblock %}
{% block content %}
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit">Sign up</button>
</form>
{% endblock %}
```
```shell=
python manage.py runserver
```
---
(c) Яценко Р.Н., 2021
[Учебный центр компьютерных технологий "Кит"](http://kit.kh.ua/)
<img src="https://i.imgur.com/Kh901c1.png" style="width: 150px; position: fixed; top: 100px; right: 10px; border: 0; box-shadow: none;">