Посібник по Django для початківців – Частина 2

21 хв. читання
03 листопада 2017

Основи

Ласкаво просимо до другої частини нашого гайду, присвяченого Django! У попередньому уроці ми встановили все, що нам необхідно. На щастя, у нас вже налаштовані Python 3.6 і Django 1.11, які працюють всередині віртуального середовища. І ми вже створили основу, з якою збираємося гратися надалі. У цьому уроці ми продовжимо писати код у тому ж проекті.

У наступному розділі, щоб надати певний контекст, ми трохи поговоримо про проект, який ми збираємося розвивати. Після цього ви дізнаєтеся про всі основні принципи Django: моделі, адміністрування, представлення, шаблони та URL-адреси.


Проект веб-дошки

Не знаю як щодо вас, але особисто я дізнаюся набагато більше, побачивши практичні приклади та фрагменти коду. Для мене важко обробити концепцію, де в прикладах ти читаєш Class А та Class B, або бачиш класичні приклади foo(bar). Мені не хочеться так з вами чинити.

Перш ніж ми потрапимо в веселу частину — гру з моделями, представленнями та всім іншим, виділимо хвилинку й дуже коротко обговоримо проект, який ми збираємося розробляти.

Якщо у вас вже є досвід веб-розробки, і ви відчуваєте, що все це занадто детально, ви просто можете продивитись зображення, щоб мати уявлення про те, що ми збираємося зробити, а потім перейти до розділу Моделі цього уроку.

Але якщо ви новачок у веб-розробці, я настійно рекомендую, щоб ви продовжили читати. Це дасть вам хороше розуміння моделювання та дизайну веб-застосунків. Веб-розробка та розробка програмного забезпечення в цілому — це не лише написання коду.

Посібник по Django для початківців – Частина 2

Діаграма варіантів використання (use case diagram)

Наш проект — дошка для дискусій (форум). Вся ідея полягає в підтримці декількох дощок (boards), які будуть поводитися як категорії. Потім, всередині певної дошки, користувач може розпочати нове обговорення, створивши нову тему. Інші користувачі можуть брати участь у цій темі, даючи відповіді.

Нам треба знайти спосіб відрізнити звичайного користувача від адміністратора, оскільки тільки адміністратори спроможні створювати нові дошки. Нижче наведено огляд основних випадків використання та роль кожного користувача:

Посібник по Django для початківців – Частина 2
Рисунок 1: Діаграма варіантів використання основних функцій, запропонованих веб-дошкою

Діаграма класів (class diagram)

З діаграми варіантів використання ми можемо почати думати про сутності нашого проекту. Сутності — це моделі, які ми створимо, і вони дуже тісно пов'язані з даними, які будуть оброблені нашим застосунком Django.

Для того, щоб ми змогли реалізувати варіанти використання, описані в попередньому розділі, нам доведеться реалізувати принаймні такі моделі: Board, Topic, Post та User.

Посібник по Django для початківців – Частина 2
Рисунок 2: Проект діаграми класів веб-дошки

Також важливо подумати про те, як моделі будуть пов'язані одна з іншою. Суцільні лінії говорять нам про те, що у моделі Topic ми повинні мати поле для визначення, до якої Board вона належить, тобто, до якої дошки належить дана тема. Подібним чином для Post потрібно поле для відображення Topic, щоб було видно, до якої теми належить даний пост, і щоб можна було лише перераховувати повідомлення, створені в межах певної тематики. Нарешті, нам знадобляться поля в обох Topic, щоб дізнатися, хто розпочав дискусію, та в Post, щоб ми могли визначити, хто відправляє відповідь.

Ми могли б також зробити зв'язок дошки з користувачем, Board та User відповідно, щоб можна було визначити, хто створив дану дошку. Але це не відноситься до застосунку. Як ви побачите пізніше, існують й інші способи відстежувати цю інформацію.

Тепер, коли у нас є представлення базового класу, треба подумати, яку інформацію нестиме кожна з цих моделей. Такі речі легко ускладнити. Тому спробуйте сконцентруватися на важливих частинах — тій інформації, яка потрібна вам для початку розробки. Пізніше ми зможемо вдосконалити нашу модель, використовуючи міграції, з якими ви познайомитесь у наступному уроці.

Але поки що основне представлення полів наших моделей буде виглядати так:

Посібник по Django для початківців – Частина 2
Рисунок 3: Діаграма класів, що підкреслює взаємозв'язок між класами (моделями)

У цій діаграмі класів особлива увага приділяється співвідношенню між моделями. Згодом, ці лінії та стрілки будуть переведені в поля.

Для моделі Board, ми почнемо з двох полів: ім'я (name) та опис (description). Поле імені має бути унікальним, щоб уникнути дублікатів назв дощок. Опис потрібен лише для того, щоб дати підказку, чому присвячена дана дошка.

Модель Topic буде складатися з чотирьох полів: тема (subject), остання дата оновлення (last update), яка буде використовуватися для визначення порядку тем, засновник теми (topic starter) — для ідентифікації користувача, що розпочав тему, а також поле дошка (board), щоб визначити, до якої Board конкретна тема належить.

Модель Post матиме поле повідомлення (message), яке буде використовуватися для зберігання тексту відповідей на пост; поле коли створено (created at) зберігатиме дату та час, і в основному використовуватиметься для упорядкування постів у межах теми; поле коли оновлено (updated at) міститиме дату та час для інформування користувачів, коли і якщо даний пост був відредагований. Подібно полям дати та часу, нам також доведеться посилатися на модель User: ким створено (created by) та ким відредаговано (updated by).

Нарешті, модель User. У діаграмі класів я згадав тільки поля ім'я (username), пароль (password), електронна пошта (email) та прапор суперкористувач (superuser), тому що це майже все, що ми наразі збираємося використовувати. Важливо зазначити, що нам не потрібно створювати модель User, оскільки Django всередині пакета contrib вже має вбудовану модель User. Її ми й будемо використовувати.

Що стосується множинності діаграми класів (числа 1, 0..* тощо), Ось як ви це читаєте:

Topic повинна бути пов'язана тільки з однією (1) Board (що означає, що вона не може бути нульовою), а Board може бути пов'язана з багатьма Topic або ні з однією (0..*). Це означає, що дошка може існувати без жодної теми.

Посібник по Django для початківців – Частина 2

Topic повинна мати принаймні один Post (початковий пост), а також може мати багато постів (1..*). Post повинен бути пов'язаний з однією, і лише однією Topic (1).

Посібник по Django для початківців – Частина 2

Topic повинна мати одного, і лише одного User, пов'язаного зі засновником теми (topic starter), який починає Topic (1). А в User може бути багато чи жодної Topic (0..*).

Посібник по Django для початківців – Частина 2

Post повинен мати одного, і лише одного User пов'язаного з: ким створено (created by) (1). User може мати багато постів або жодного (0..*). Друге з'єднання між Post і User є прямою асоціацією (див. стрілку в кінці лінії), що означає, що ми зацікавлені лише в одній стороні відносин — те, що User відредагував даний Post. Він буде переведений на поле ким відредаговано (updated by). Множинність 0..1 означає, що оновлене поле може бути нульовим (пост не редагувався) і, щонайбільше, може бути пов'язаний лише з одним User.

Посібник по Django для початківців – Частина 2

Інший спосіб намалювати цю діаграму класів — це зробити наголос на поля, а не на взаємозв'язок між моделями:

Посібник по Django для початківців – Частина 2
Рисунок 4: Діаграма класів, що підкреслює атрибути (поля) класів (моделей)

Представлення вище еквівалентно попередньому, і також воно ближче до того, що ми збираємося розробляти, використовуючи API Django Models. У цьому представленні ми бачимо більш чітко, що в моделі Post асоціації topic, created by та updated by стали полями моделі. Інша цікава річ, яку треба відзначити, це те, що в моделі Topic ми тепер маємо операцію (метод класу), яка називається posts(). Ми маємо намір досягти цього шляхом реалізації зворотної взаємодії, де Django автоматично виконає запит у базі даних, щоб повернути список всіх постів, що належать до певної теми.

Добре, достатньо UML! Щоб намалювати діаграми, представлені в цьому розділі, я використовував інструмент StarUML.

Каркаси

Провівши деякий час розробляючи моделі застосунків, я хотів би створити кілька каркасів для визначення того, що потрібно зробити, а також мати чітке уявлення про те, куди ми рухаємося.

Посібник по Django для початківців – Частина 2

Потім, на основі каркасів ми зможемо отримати більш глибоке розуміння сутностей, які беруть участь у застосунку.

По-перше, нам потрібно показати всі дошки на домашній сторінці:

Посібник по Django для початківців – Частина 2
Рисунок 5: Домашня сторінка каркасу проекту, яка містить список всіх доступних дощок.

Якщо користувач натискає на посилання, скажімо, на дошці Django, то воно повинне перелічити всі теми:

Посібник по Django для початківців – Частина 2
Рисунок 6: каркас проекту, який містить список усіх тем у дошці Django.

Тут у нас є два основні шляхи: або користувач натискає на кнопку «нова тема», щоб створити нову тему, або користувач натискає на саму тему, щоб переглянути або взяти участь у дискусії.

Екран «нова тема»:

Посібник по Django для початківців – Частина 2
Рисунок 7: Екран нової теми

Тепер екран теми, який відображає пости та обговорення:

Посібник по Django для початківців – Частина 2
Рисунок 8: Екран списку постів з теми

Якщо користувач натискає кнопку відповіді, він побачить нижче наведене вікно з підсумком повідомлень у зворотному порядку (спочатку найновіше):

Посібник по Django для початківців – Частина 2
Рисунок 9: Екран з відповідями на тему

Для того, щоб намалювати ваші каркаси, ви можете скористатися draw.io, це безкоштовно.


Моделі

Моделі в основному являють собою макет бази даних вашого застосунку. У цьому розділі ми збираємося створити представлення Django класів, змодельованих нами у попередньому розділі: Board, Topic та Post. Модель User вже визначена всередині вбудованої програми під назвою auth, яка перелічена в нашій конфігурації INSTALLED_APPS під простором імен django.contrib.auth.

Ми виконаємо всю роботу всередині файлу boards/models.py. Ось як ми представляємо діаграму класів (див. рис. 4). у застосунку Django:

from django.db import models
from django.contrib.auth.models import User


class Board(models.Model):
    name = models.CharField(max_length=30, unique=True)
    description = models.CharField(max_length=100)


class Topic(models.Model):
    subject = models.CharField(max_length=255)
    last_updated = models.DateTimeField(auto_now_add=True)
    board = models.ForeignKey(Board, related_name='topics')
    starter = models.ForeignKey(User, related_name='topics')


class Post(models.Model):
    message = models.TextField(max_length=4000)
    topic = models.ForeignKey(Topic, related_name='posts')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(null=True)
    created_by = models.ForeignKey(User, related_name='posts')
    updated_by = models.ForeignKey(User, null=True, related_name='+')

Всі моделі є підкласом класу django.db.models.Model. Кожен клас буде перетворений у таблиці бази даних. Кожне поле представляється екземплярами підкласів django.db.models.Field (вбудоване ядро Django) і буде переведено в стовпці бази даних.

Поля CharField, DateTimeField тощо — це все підкласи django.db.models.Field, і вони включаються в ядро Django — готові до використання.

Тут для визначення наших моделей ми тільки використовуємо поля CharField, TextField, DateTimeField та ForeignKey. Але Django пропонує широкий спектр можливостей для представлення різних типів даних, таких як IntegerField, BooleanField, DecimalField та багато інших. Ми за необхідністю будемо звертатися до них.

Деякі поля, такі як CharField, мають обов'язкові аргументи. Ми завжди повинні встановлювати max_length. Ця інформація буде використана для створення стовпця бази даних. Django повинен знати, наскільки великим має бути стовпчик бази даних. Параметр max_length також буде використовуватися API Django Forms для перевірки введення користувача. Більше про це пізніше.

У визначенні моделі Board, зокрема в полі name, ми також встановлюємо параметр unique=True, як випливає з назви, це забезпечить унікальність поля на рівні бази даних.

У моделі Post, поле created_at має необов'язковий параметр auto_now_add, для нього встановлене значення True. Це дасть вказівку Django встановити поточну дату та час створення об'єкта Post.

Одним зі способів створення відношень між моделями є використання поля ForeignKey. Воно створить зв'язок між моделями та належні відношення на рівні бази даних. ForeignKey очікує позиційний параметр з посиланням на модель, до якої він буде відноситись.

Наприклад, у моделі Topic поле board — це ForeignKey для моделі Board. Воно каже Django, що екземпляр Topic відноситься лише до одного екземпляра Board. Параметр related_name буде використовуватися для створення зворотного зв'язку, коли екземпляри Board матимуть доступ до списку екземплярів Topic, що до нього належать.

Django автоматично створює цей зворотній зв'язок — related_name є необов'язковим. Але якщо ми не встановимо для нього назву, Django генеруватиме його з назвою: (class_name)_set. Наприклад, у моделі Board екземпляри Topic будуть доступні за властивістю topic_set. Замість цього ми перейменували його просто в topics, щоб це виглядало більш природнім.

Нижче ви можете побачити порівняння між діаграмою класів та вихідним кодом для генерування моделей з Django. Зелені лінії показують, як ми обробляємо зворотні зв'язки.

Посібник по Django для початківців – Частина 2

На цьому етапі ви можете запитати себе: «як щодо первинних ключів/ID»? Якщо ми не задамо первинний ключ для моделі, Django автоматично згенерує його для нас. У наступному розділі ви краще побачите, як це працює.

Міграція моделей

Наступний крок — сказати Django створити базу даних, щоб ми могли почати її використовувати.

Відкрийте інструменти командного рядка, активуйте віртуальне середовище, перейдіть до теки, де знаходиться файл manage.py, і запустіть наступні команди:

python manage.py makemigrations

Як вивід ви отримаєте щось на зразок цього:

Migrations for 'boards':
  boards/migrations/0001_initial.py
    - Create model Board
    - Create model Post
    - Create model Topic
    - Add field topic to post
    - Add field updated_by to post

На цьому етапі Django створив файл з ім'ям 0001_initial.py всередині теки boards/migrations. Він відображає поточний стан моделей нашого застосунку. На наступному кроці, Django буде використовувати цей файл для створення таблиць і стовпців.

Файли міграції перетворюються в оператори SQL. Якщо ви знайомі з SQL, ви можете запустити наступну команду для перевірки інструкцій SQL, які будуть виконуватись у базі даних:

python manage.py sqlmigrate boards 0001

Якщо ви не знайомі з SQL, не хвилюйтеся. У цій серії ми не будемо працювати безпосередньо з SQL. Вся робота буде виконуватися тільки за допомогою Django ORM, який є рівнем абстракції, який взаємодіє з базою даних.

Тепер наступний крок — застосувати згенеровану нами міграцію до бази даних:

python manage.py migrate

Вивід виглядатиме якось так:

Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying boards.0001_initial... OK
  Applying sessions.0001_initial... OK
```	
Оскільки це вперше, коли ми переміщуємо базу даних, команда `migrate` також застосувала наявні файли міграції зі застосунків contrib Django, перелічених у `INSTALLED_APPS`. Це очікувано.

Рядок `Applying boards.0001_initial... OK` — це міграція, яку ми створили на попередньому кроці.

Ось і все! Наша база даних готова до використання.

![](https://image.prntscr.com/image/2U6mGOrZSqiGWM5yFWw8Yg.png)

<blockquote>
    <p>
        Примітка. Важливо відзначити, що SQLite — це база даних виробничої якості. SQLite використовується багатьма компаніями у тисячах продуктів, таких як всі пристрої Android та iOS, усі основні браузери, Windows 10, macOS тощо. Вона просто не підходить для всіх випадків. SQLite не зрівняється з такими базами даних, як MySQL, PostgreSQL або Oracle. Веб-сайти великого обсягу, застосунки з великою інтенсивністю запису, дуже великі набори даних, високий рівень паралелізму — це деякі ситуації, які в кінцевому підсумку можуть призвести до проблеми через використання SQLite. Ми будемо використовувати SQLite під час розробки нашого проекту, оскільки це зручно, і нам не буде потрібно встановлювати щось іще. Коли ми будемо впроваджувати наш проект у продакшн, то перейдемо до PostgreSQL. Для простих сайтів вона добре підходить. Але для складних сайтів рекомендується використовувати одну й ту саму базу даних для розробки й продакшена.
    </p>
    <footer>
    </footer>
</blockquote>

#### **Експериментування з Models API**
Однією з найважливіших переваг розробки з Python є інтерактивна оболонка. Я використовую її весь час. Це швидкий спосіб відлагодити речі й поекспериментувати з бібліотеками та API.

Ви можете запустити оболонку Python з нашим проектом, завантаженим за допомогою утиліти **manage.py**:

python manage.py shell

Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole)


Це дуже схоже на виклик інтерактивної консолі, просто набравши `python`, крім того, що, коли ми використовуємо `python manage.py shell`, ми додаємо наш проект до `sys.path` і завантажуємо Django. Це означає, що ми можемо імпортувати наші моделі та будь-який інший ресурс у рамках проекту та гратися з ним.

Почнімо з імпортування класу **Board**:
```Python
from boards.models import Board

Для створення нового об'єкту ми можемо зробити наступне:

board = Board(name='Django', description='This is a board about Django.')

Щоб зберегти цей об'єкт у базі даних, ми повинні викликати метод save:

board.save()

Метод save використовується як для створення так і для оновлення об'єктів. Тут Django створив новий об'єкт, оскільки екземпляр Board не мав id. Після збереження в перший раз, Django автоматично встановить id:

board.id
1

Ви можете отримати доступ до решти полів як до атрибутів Python:

board.name
'Django'
board.description
'This is a board about Django.'

Для оновлення значення ми могли б прописати:

board.description = 'Django discussion board.'
board.save()

Кожна модель Django має спеціальний атрибут; ми називаємо його диспетчером моделей (Model Manager). Ви можете отримати доступ до нього за допомогою атрибута Python objects. В основному він використовується для виконання запитів у базі даних. Наприклад, ми могли б використати його для безпосереднього створення нового об'єкта Board:

board = Board.objects.create(name='Python', description='General discussion about Python.')
board.id
2
board.name
'Python'

Отже, зараз у нас є дві дошки. Ми можемо використовувати об'єкти, для відображення всіх наявних дощок в базі даних:

Board.objects.all()
<QuerySet [<Board: Board object>, <Board: Board object>]>

Результатом став QuerySet. Ми дізнаємося більше про це пізніше. В основному, це список об'єктів з бази даних. Ми бачимо, що у нас є два об'єкти, але ми можемо лише читати об'єкт Board. Це тому, що ми не визначили метод __str__ у моделі Board.

Метод __str__ — це рядкове представлення об'єкта. Ми можемо використовувати назву дошки для її представлення.

Спочатку вийдіть з інтерактивної консолі:

exit()

Тепер відредагуйте файл models.py всередині застосунку boards:

class Board(models.Model):
    name = models.CharField(max_length=30, unique=True)
    description = models.CharField(max_length=100)

    def __str__(self):
        return self.name

Спробуємо виконати запит ще раз. Відкрийте інтерактивну консоль знову:

python manage.py shell
from boards.models import Board

Board.objects.all()
<QuerySet [<Board: Django>, <Board: Python>]>

Набагато краще, так?

Ми можемо розглядати цей QuerySet як список. Скажімо, ми хочемо його перебрати й вивести опис кожної дошки:

boards_list = Board.objects.all()
for board in boards_list:
    print(board.description)

Результат виглядав би так:

Django discussion board.
General discussion about Python.

Аналогічним чином ми можемо використовувати диспетчер моделей для запиту до бази даних і повернення одного об'єкта. Для цього ми використовуємо метод get:

django_board = Board.objects.get(id=1)

django_board.name
'Django'

Але ми повинні бути обережні з такою операцією. Якщо ми спробуємо отримати об'єкт, який не існує, наприклад, дошка з id=3, вона викличе виняток:

board = Board.objects.get(id=3)

boards.models.DoesNotExist: Board matching query does not exist.

Ми можемо використовувати метод get з будь-яким полем моделі, але бажано використовувати поле, яке може однозначно ідентифікувати об'єкт. В іншому випадку, запит може повернути більше одного об'єкта, що спричинить виняток.

Board.objects.get(name='Django')
<Board: Django>

Зверніть увагу, що запит є чутливим до регістру, нижній регістр «django» не збігатиметься:

Board.objects.get(name='django')
boards.models.DoesNotExist: Board matching query does not exist.

Коротко про операції з моделями

Нижче наведено короткий опис методів та операцій, про які ми дізналися в цьому розділі, використовуючи модель Board як довідкову. Верхня Board відноситься до класу, нижня board відноситься до екземпляра (або об'єкту) класу моделі Board:

Операція Приклад коду
Створення об'єкту без його збереження board = Board()
Зберегти об'єкт (створення або редагування) board.save()
Створити й зберегти об'єкт у базі даних Board.objects.create(name='...', description='...')
Список об'єктів Board.objects.all()
Отримайте один об'єкт, ідентифікований полем Board.objects.get(id=1)

У наступному розділі ми почнемо писати представлення та відображати наші дошки на HTML-сторінках.


Представлення, шаблони та статичні файли

На даний момент у нас вже є представлення з назвою home, яке відображає «Hello, World!» На головній сторінці нашої програми.

myproject/urls.py

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

from boards import views

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

boards/views.py

from django.http import HttpResponse

def home(request):
    return HttpResponse('Hello, World!')

Ми можемо використовувати це як нашу точку відліку. Якщо ви згадаєте наші каркаси, на рис. 5 показано, як повинна виглядати домашня сторінка. Що ми хочемо зробити — це показати список дощок разом із деякою іншою інформацією.

Перше, що потрібно зробити, це імпортувати модель Board та перелічити всі наявні дошки:

boards/views.py

from django.http import HttpResponse
from .models import Board

def home(request):
    boards = Board.objects.all()
    boards_names = list()

    for board in boards:
        boards_names.append(board.name)

    response_html = '<br>'.join(boards_names)

    return HttpResponse(response_html)

І результатом буде ця проста HTML-сторінка: Посібник по Django для початківців – Частина 2

Але зупинімося прямо тут. Ми не зайдемо занадто далеко рендерячи HTML таким чином. Для цього простого представлення все, що нам потрібно — це список дощок; тоді частина, пов'язана з рендерингом, є роботою для Django Template Engine.

Встановлення Django Template Engine

Створіть нову теку з назвою templates поряд з теками boards та mysite:

myproject/
 |-- myproject/
 |    |-- boards/
 |    |-- myproject/
 |    |-- templates/   <-- тут!
 |    +-- manage.py
 +-- venv/

Тепер у теці templates створіть файл HTML із назвою home.html:

templates/home.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Boards</title>
  </head>
  <body>
    <h1>Boards</h1>

    {% for board in boards %}
      {{ board.name }} <br>
    {% endfor %}

  </body>
</html>

У наведеному вище прикладі ми змішуємо вихідний HTML з деякими спеціальними тегами {% for ... in ...%} і {{variable}}. Вони є частиною Django Template Language. У наведеному вище прикладі показано, як ітерувати список об'єктів використовуючи for. {{board.name}} відображає назву дошки у шаблоні HTML, генеруючи динамічний HTML-документ.

Перш ніж ми зможемо використовувати цю HTML-сторінку, нам потрібно сказати Django, де знайти шаблони нашого застосунку.

Відкрийте settings.py всередині каталогу myproject, знайдіть змінну TEMPLATES і встановіть ключ DIRS на os.path.join(BASE_DIR, 'templates'):

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates')
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

В основному цей рядок шукає повний шлях до теки вашого проекту та додає до неї «/ templates».

Ми можемо відлагодити це за допомогою оболонки Python:

python manage.py shell
from django.conf import settings

settings.BASE_DIR
'/Users/vitorfs/Development/myproject'

import os

os.path.join(settings.BASE_DIR, 'templates')
'/Users/vitorfs/Development/myproject/templates'

Бачите? Воно просто вказує на теку templates, яку ми створили на попередніх кроках.

Тепер ми можемо оновити наше представлення home:

from django.shortcuts import render
from .models import Board

def home(request):
    boards = Board.objects.all()
    return render(request, 'home.html', {'boards': boards})

Отримана HTML:

Посібник по Django для початківців – Частина 2

Ми можемо покращити HTML-шаблон, щоб натомість користуватися таблицею:

templates/home.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Boards</title>
  </head>
  <body>
    <h1>Boards</h1>

    <table border="1">
      <thead>
        <tr>
          <th>Board</th>
          <th>Posts</th>
          <th>Topics</th>
          <th>Last Post</th>
        </tr>
      </thead>
      <tbody>
        {% for board in boards %}
          <tr>
            <td>
              {{ board.name }}<br>
              <small style="color: #888">{{ board.description }}</small>
            </td>
            <td>0</td>
            <td>0</td>
            <td></td>
          </tr>
        {% endfor %}
      </tbody>
    </table>
  </body>
</html>

Посібник по Django для початківців – Частина 2

Тестування домашньої сторінки

Посібник по Django для початківців – Частина 2

Це буде повторюваним предметом, на протязі усього гайду ми разом вивчимо різні концепції та стратегії.

Напишімо наш перший тест. На даний момент ми будемо працювати в файлі tests.py всередині застосунку boards:

boards/tests.py

from django.core.urlresolvers import reverse
from django.test import TestCase

class HomeTests(TestCase):
    def test_home_view_status_code(self):
        url = reverse('home')
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)

Це надзвичайно простий тестовий випадок (test case), але надзвичайно корисний. Ми перевіряємо код статусу відповіді. Код статусу 200 означає успіх.

Ми можемо перевірити код статусу відповіді в консолі: Посібник по Django для початківців – Частина 2

Якби було б неперехоплене виключення (uncaught exception) чи щось інше, Django замість цього повернув би код статусу 500, що означає внутрішню помилку сервера (Internal Server Error). Тепер уявіть, що наш застосунок має 100 представлень. Якби ми написали лише цей простий тест для всіх наших представлень, за допомогою лише однієї команди, ми могли б перевірити, чи всі представлення повертають код успіху. Без автоматизації тестів нам потрібно буде перевіряти кожну сторінку окремо.

Щоб виконати тестовий набір Django:

Python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.041s

OK
Destroying test database for alias 'default'...

Тепер ми можемо перевірити, чи повернув Django правильне представлення функції для запитуваної URL-адреси. Це також корисний тест, тому що, просуваючись з розробкою, ви побачите, що модуль urls.py може стати дуже великим і складним. Конфігурація URL — це вирішення регулярних виразів. Є деякі випадки, коли ми маємо дуже допустиму URL-адресу, тому Django може повернути неправильну функцію представлення.

Ось як ми це робимо:

boards/tests.py

from django.core.urlresolvers import reverse
from django.urls import resolve
from django.test import TestCase
from .views import home

class HomeTests(TestCase):
    def test_home_view_status_code(self):
        url = reverse('home')
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)

    def test_home_url_resolves_home_view(self):
        view = resolve('/')
        self.assertEquals(view.func, home)

У другому тесті ми використовуємо функцію resolve. Django використовує її для перевірки відповідності запитуваної URL-адреси зі списком URL-адрес, перерахованих у модулі urls.py. Цей тест дозволить переконатися, що URL /, яка є кореневою URL-адресою, повертає представлення home.

Протестуємо знову:

Python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.027s

OK
Destroying test database for alias 'default'...

Щоб побачити більш детальну інформацію про виконання тесту, встановіть verbosity на більш високий рівень:

Python manage.py test --verbosity=2
Creating test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...
Operations to perform:
  Synchronize unmigrated apps: messages, staticfiles
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying boards.0001_initial... OK
  Applying sessions.0001_initial... OK
System check identified no issues (0 silenced).
test_home_url_resolves_home_view (boards.tests.HomeTests) ... ok
test_home_view_status_code (boards.tests.HomeTests) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.017s

OK
Destroying test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...

Verbosity визначає кількість повідомлень та розмір інформації про відладку, які будуть виведені у консолі; 0 — не виводиться, 1 — нормальний вивід, а 2 — детальний вивід.

Встановлення статичних файлів

Статичні файли — це CSS, JavaScript, шрифти, зображення або будь-які інші ресурси, які ми можемо використовувати для створення користувацького інтерфейсу.

Як і раніше, Django не обслуговує ці файли. За винятком процесу розробки, щоб полегшити нам життя. Але Django надає деякі функції, які допомагають нам керувати статичними файлами. Ці функції доступні в застосунку django.contrib.staticfiles, вже вказаного в конфігурації INSTALLED_APPS.

За наявності такої кількості бібліотек фронтенд компонентів, немає ніякої необхідності того, щоб продовжувати рендерити основні HTML-документи. Ми з легкістю можемо додати Bootstrap 4 до нашого проекту. Bootstrap — це інструментарій з відкритим вихідним кодом для розробки з HTML, CSS та JavaScript.

У кореневому каталозі проекту поруч із теками boards, templates та myproject створіть нову теку з назвою static, а в ній, у свою чергу, створіть теку з назвою css:

myproject/
 |-- myproject/
 |    |-- boards/
 |    |-- myproject/
 |    |-- templates/
 |    |-- static/       <-- тут
 |    |    +-- css/     <-- і тут
 |    +-- manage.py
 +-- venv/

Перейдіть на getbootstrap.com та завантажте останню версію: Посібник по Django для початківців – Частина 2
Завантажте скомпільовані версії CSS та JS.

На комп'ютері вилучіть файл bootstrap-4.0.0-beta-dist.zip, завантажений з сайту Bootstrap, скопіюйте файл css/bootstrap.min.css у теку css нашого проекту:

myproject/
 |-- myproject/
 |    |-- boards/
 |    |-- myproject/
 |    |-- templates/
 |    |-- static/
 |    |    +-- css/
 |    |         +-- bootstrap.min.css    <-- тут
 |    +-- manage.py
 +-- venv/

Наступний крок — вказати Django, де знайти статичні файли. Відкрийте settings.py, прокрутіть донизу та одразу після STATIC_URL, додайте наступне:

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

Так само, як і з текою TEMPLATES, пам'ятаєте?

Тепер нам потрібно завантажити статичні файли (файл CSS Bootstrap) в наш шаблон :

templates/home.html

{% load static %}<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Boards</title>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
  </head>
  <body>
    <!-- тіло обмежене для стислості ... -->
  </body>
</html>

Спочатку ми завантажуємо теги шаблону застосунку Static Files, використовуючи {% load static%} на початку шаблону.

Тег шаблону {% static %} використовується для складання URL, де живе ресурс. У цьому випадку {% static 'css/bootstrap.min.css'%} поверне /static/css/bootstrap.min.css, що еквівалентно http://127.0.0.1:8000/static/css/bootstrap.min.css.

Тег шаблону {% static %} використовує конфігурацію STATIC_URL у settings.py, щоб скласти кінцеву URL-адресу. Наприклад, якщо б ви розмістили свої статичні файли в субдомені, як https://static.example.com/, то ми встановили б STATIC_URL = https: //static.example.com/, а потім {% static 'css/bootstrap. min.css '%} повернув би https://static.example.com/css/bootstrap.min.css.

Якщо нічого з цього не має сенсу для вас на даний момент, не хвилюйтеся. Просто пам'ятайте, що треба використовувати {% static %} щоразу, коли потрібно послатися на CSS, JavaScript або файл зображення. Пізніше, коли ми почнемо працювати з розгортанням, то обговоримо це детальніше. Наразі ми все налаштували.

Оновлюючи сторінку 127.0.0.1:8000, можна побачити, що все працює: Посібник по Django для початківців – Частина 2
Тепер ми можемо відредагувати шаблон таким чином, щоб скористатися перевагами Bootstrap CSS:

{% load static %}<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Boards</title>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
  </head>
  <body>
    <div class="container">
      <ol class="breadcrumb my-4">
        <li class="breadcrumb-item active">Boards</li>
      </ol>
      <table class="table">
        <thead class="thead-inverse">
          <tr>
            <th>Board</th>
            <th>Posts</th>
            <th>Topics</th>
            <th>Last Post</th>
          </tr>
        </thead>
        <tbody>
          {% for board in boards %}
            <tr>
              <td>
                {{ board.name }}
                <small class="text-muted d-block">{{ board.description }}</small>
              </td>
              <td class="align-middle">0</td>
              <td class="align-middle">0</td>
              <td></td>
            </tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
  </body>
</html>

Тепер результат такий: Посібник по Django для початківців – Частина 2
Дотепер ми додавали нові дошки за допомогою інтерактивної консолі (python manage.py shell). Але нам потрібен кращий спосіб це робити . У наступному розділі ми впровадимо адміністративний інтерфейс для управління сайтом.


Основи Django Admin

Коли ми починаємо новий проект, Django вже сконфігурований з допомогою Django Admin, вказаного в INSTALLED_APPS.

Посібник по Django для початківців – Частина 2

Хорошим варіантом використання Django Admin є, наприклад, блог; він може бути використаний авторами для написання та публікації статей. Іншим прикладом є сайт електронної комерції, де працівники можуть створювати, редагувати або видаляти продукти.

Наразі ми налаштуємо Django Admin для підтримки дощок нашого застосунку.

Почнемо зі створення акаунту адміністратора:

Python manage.py createsuperuser

Слідуйте інструкціям:

Username (leave blank to use 'vitorfs'): admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.

Тепер відкрийте URL у браузері: http://127.0.0.1:8000/admin/ Посібник по Django для початківців – Частина 2
Введіть ім'я користувача та пароль для входу в інтерфейс адміністрування: Посібник по Django для початківців – Частина 2
Він вже включає деякі налаштовані функції. Тут можна додавати користувачів та групи для керування правами доступу. Ми будемо вивчати більше цих понять пізніше.

Додати модель Board дуже просто. Відкрийте файл admin.py у теці boards і додайте наступний код:

boards/admin.py

from django.contrib import admin
from .models import Board

admin.site.register(Board)

Збережіть файл admin.py та оновіть сторінку в браузері: Посібник по Django для початківців – Частина 2
І це все! Він готовий до використання. Клацніть на Boards, щоб переглянути список наявних дощок: Посібник по Django для початківців – Частина 2
Ми можемо додати нову дошу, натискачи на кнопку Add Board: Посібник по Django для початківців – Частина 2
Натисніть на кнопку save: Посібник по Django для початківців – Частина 2
Ми можемо перевірити, чи все працює, відкривши URL http://127.0.0.1:8000: Посібник по Django для початківців – Частина 2


Висновки

У цьому уроці ми розглянули багато нових концепцій. Ми визначили деякі вимоги до нашого проекту, створили перші моделі, зробили міграцію бази даних, почали гратися з Models API. Ми створили наше перше представлення та написали деякі юніт-тести. Ми також налаштували Template Django Engine, статичні файли та додали бібліотеку Bootstrap 4 до проекту. Нарешті, у нас було дуже коротке знайомство з інтерфейсом Django Admin.

Я сподіваюся, що вам сподобалась друга частина цієї навчальної серії! У наступній частині на нас чекає маршрутизація Django, API форм, шаблони багаторазового використання та ще більше тестування.

Вихідний код проекту доступний на GitHub. Поточний стан проекту можна знайти за тегом релізу v0.2-lw. Нижче наведене посилання, яке приведе вас до потрібного місця:

https://github.com/sibtc/django-beginners-guide/tree/v0.2-lw

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація