Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии и методы программирования. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
15.08.2026
Размер:
1 Мб
Скачать

Создадим общий шаблон (templates/base.html) с базовой структурой для всех HTML-файлов. В тегах <title> и <body> можно встроить HTML-блоки и заменить содержимое, так как информация на всех страницах будет разной. Пример:

<body>

{% block body %} {% endblock %} </body>

index.html после этого можно переписать следующим образом:

{% extends 'base.html' %}

{% block body %} <h1>Основная страница</h1> {% endblock %}

Для создания CSS-стилей создается папка static/css, в ней соответственно создается стандартный файл main.css. Язык CSS используется для оформления структурированных документов, например HTML-до- кументов. Синтаксис – это плоский список CSS-правил. CSS-правило состоит из селектора и перечня свойств и их значений:

селектор { свойство: значение;

свойство: значение;

}

Селектор находится в начале CSS-правила, до фигурных скобок, и определяет, к каким HTML-элементам применятся свойства и значения из правила. Простейшие (и самые популярные) селекторы – это селекторы по тегам и по классам. Селекторы по тегам содержат имя тега без символов < и > и применяются ко всем подходящим тегам. Селекторы по классам начинаются с точки, за которой идет имя класса, и применяютсяковсемтегам сподходящиматрибутомclass. Настраницеможет быть несколько списков, и стили применятся ко всем спискам, даже к тем, которые вы менять не хотели. Чтобы избежать таких ситуаций, лучше не использовать селекторы по тегам или использовать их как можно реже.

41

Если у CSS-правил отличаются только селекторы, а свойства и значения одинаковые, то их можно сгруппировать через запятую. Список свойств и значений находится внутри фигурных скобок CSS-правила. Свойство определяет, какую характеристику внешнего вида мы хотим изменить, а значение – как именно.

В main.css пропишем следующее (серый фон):

body { background: grey;

}

Файлmain.css подключаетсявbase.html (передтегом<title>) следующим образом:

<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css')}}">

Для корректного отображения допишем первую строку в index.html: from flask import Flask, render_template, url_for

Вместо ручного прописывания CSS-файлов можно также использовать готовые стили – например, от Bootstrap:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">

Работа с БД SQLite

ДляработысбазамиданныхтребуетсяимпортироватьSQLAlchemy: from flask_sqlalchemy import SQLAlchemy

После создания Flask-объекта подключим SQLite:

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'

Создаем объект базы данных: db = SQLAlchemy(app)

42

Далее можно записать как один, так и несколько классов, каждый из которых будет выполнять роль определенной таблицы в базе данных. Для описания полей внутри таблицы необходимо прописать переменныевнутриклассов. Вкаждуюпеременнуюустанавливаетсяопределенное значение, что соответствует типу устанавливаемых данных в поле таблицы. Пример:

class Article(db.Model):

id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) intro = db.Column(db.String(300), nullable=False) text = db.Column((db.Text), nullable=False)

date = db.Column(db.DateTime, default=datetime.utcnow)

В данном случае создается таблица «Статьи» с полями «Идентификатор» (является целым числом и первичным ключом – уникальным значением), «Название», «Вступление» (строковый тип, не может быть пустым), «Текст» (текстовый тип, не может быть пустым) и «Дата» (тип «дата» созначениемпоумолчанию«текущаядата»). Дляиспользования datetime.utcnow необходимо подключить datetime:

from datetime import datetime

При получении объекта из базы данных всегда возвращается идентификатор записи. С такой информацией мало что можно сделать, поэтому лучше в классе модели дописывать метод «__repr__». В нем можно указать, какое значение будет возвращается при получении объекта из БД:

def __repr__(self):

return '<Article %r>' % self.id

Для регистрации базы данных в проекте используется терминал PyCharm. Переходим в интерактивный режим:

flask shell

Импортируем объект: from app import db

43

Вызываем функцию создания: db.create_all()

Выходим из интерактивного режима: exit()

В итоге создан файл blog.db. Создадим файл create-article.html в папкеtemplates ипропишемформудлядобавлениястатьивбазуданных:

<div class="container mt-5"> <h1>Добавление статьи</h1> <form method="post">

<input type="text" name="title" id="title" class="form-control"><br>

<textarea name="intro" id="intro" class= "form-control"></textarea><br>

<textarea name="text" id="text" class= "form-control"></textarea><br>

<input type="submit" class="btn btn-success" value="Отправить"><br>

</form>

</div>

В основном файле отследим файл create-article.html и реализуем добавление статей:

@app.route('/create-article', methods=['POST', 'GET'])

def create_article():

if request.method == "POST": title = request.form['title'] intro = request.form['intro'] text = request.form['text']

article = Article(title=title, intro=intro, text=text)

try:

db.session.add(article)

44

db.session.commit() return redirect('/') except:

return "При добавлении возникла ошибка" else:

return render_template("create-article.html")

Здесь используются исключения. Исключения – еще один тип данных в языке Python. Исключения необходимы для того, чтобы сообщать программисту об ошибках. Рассмотрим иерархию встроенных в Python исключений, хотя иногда вам могут встретиться и другие, так как программисты могут создавать собственные исключения.

BaseException – базовое исключение, от которого берут начало все остальные.

SystemExit – исключение, порождаемое функцией sys.exit при выходе из программы.

KeyboardInterrupt – порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).

GeneratorExit – порождается при вызове метода close объекта

generator.

Exception – здесь заканчиваются полностью системные исключения (которые лучше не трогать) и начинаются обыкновенные, с которыми можно работать.

StopIteration – порождается встроенной функцией next, если

витераторе больше нет элементов.

ArithmeticError – арифметическая ошибка.

FloatingPointError – порождается при неудачном выполнении операции с плавающей точкой. На практике встречается нечасто.

OverflowError – возникает, когдарезультатарифметическойоперации слишком велик для представления. Не появляется при обычной работесцелымичислами(таккакPython поддерживаетдлинныечисла), но может возникать в некоторых других случаях.

ZeroDivisionError – деление на ноль.

AssertionError – выражение в функции assert ложно.

AttributeError – объект не имеет данного атрибута(значения или метода).

45

BufferError – операция, связанная с буфером, не может быть выполнена.

EOFError – функциядостиглаконцафайлаинесмоглапрочитать то, что хотела.

ImportError – не удалось импортирование модуля или его атри-

бута.

LookupError – некорректный индекс или ключ.

IndexError – индекс не входит в диапазон элементов.

KeyError – несуществующий ключ (в словаре, множестве или другом объекте).

MemoryError – недостаточно памяти.

NameError – не найдено переменной с таким именем.

UnboundLocalError – сделана ссылка на локальную переменную

вфункции, но переменная не определена ранее.

OSError – ошибка, связанная с системой.

BlockingIOError

ChildProcessError – неудача при операции с дочерним процес-

сом.

ConnectionError – базовый класс для исключений, связанных с подключениями.

BrokenPipeError

ConnectionAbortedError

ConnectionRefusedError

ConnectionResetError

FileExistsError – попытка создания файла или директории, которые уже существуют.

FileNotFoundError – файл или директория не существует.

InterruptedError – системный вызов прерван входящим сигна-

лом.

IsADirectoryError – ожидался файл, но это директория.

NotADirectoryError – ожидалась директория, но это файл.

PermissionError – не хватает прав доступа.

ProcessLookupError – указанного процесса не существует.

TimeoutError – закончилось время ожидания.

46

ReferenceError – попытка доступа к атрибуту со слабой ссылкой.

RuntimeError – возникает, когда исключение не попадает ни под одну из других категорий.

NotImplementedError – возникает, когда абстрактные методы класса требуют переопределения в дочерних классах.

SyntaxError – синтаксическая ошибка.

IndentationError – неправильные отступы.

TabError – смешивание в отступах табуляции и пробелов.

SystemError – внутренняя ошибка.

TypeError – операция применена к объекту несоответствующего

типа.

ValueError – функция получает аргумент правильного типа, но некорректного значения.

UnicodeError – ошибка, связанная с кодированием/раскодированием Unicode в строках.

UnicodeEncodeError – исключение, связанное с кодированием

Unicode.

UnicodeDecodeError – исключение, связанное с декодированием

Unicode.

UnicodeTranslateError – исключение, связанное с переводом

Unicode.

Warning – предупреждение.

Теперь, зная, когда и при каких обстоятельствах могут возникнуть исключения, мы можем их обрабатывать. Для обработки исключений используется конструкция try except. Разберем пример с ZeroDivisionError:

try:

k = 1 / 0

except ZeroDivisionError:

print ("Деление на 0 запрещено")

В данном случае выдается сообщение о невозможности деления на ноль. В блоке try мы выполняем инструкцию, которая может породить исключение, а в блоке except мы перехватываем их. При этом перехватываются как само исключение, так и его потомки. Например,

47

перехватываяArithmeticError, мытакжеперехватываемFloatingPointError, OverflowError и ZeroDivisionError.

Следует отметить, что необходимо импортировать из Flask request и redirect. Объект request используется для получения доступа к входящим данным в Flask. В объекте request хранятся все входящие данные запроса, включая тип MIME, источник, IP-адрес, необработанные данные, метод HTTP, заголовки и др. Объект redirect при вызове возвращает объект ответа и перенаправляет пользователя в другое целевое местоположение.

Функция create_article проверяет метод передачи данных. Если методом является POST, то из формы HTML берутcя значения title, intro и text и создается article на основе класса Article. Далее производится попытка добавления article в базу данных при помощи session.add() и session.commit(). В случае корректной об-

работки происходит перенаправление, в обратном случае выводится ошибка.

Отображение данных из БД (модели)

Для взаимодействия с базой данных необходимо использовать модели. Модель представляет собой прямой проводник к определенной таблице в БД. Через модель можно создавать новые записи, обновлять уже существующие, удалять записи и получать записи для дальнейшего отображения в шаблонах.

Создадим файл templates/posts.html для отображения данных из таблицы базы данных. Чтобы получить записи из таблицы, нужно создать объект на основе вашей модели и далее обратиться к одной из многих доступных функций. Реализуем отображение статей:

@app.route('/posts') def posts():

articles = Article.query.order_by(Article.date.desc()).all()

return render_template("posts.html", articles=articles)

48

В этом случае производится запрос query к модели Article, который выдает все записи, отсортированные по дате от более новых к старым. Результат записывается в модель articles и передаётся на страницу posts.html. В файле posts.html пропишем следующую конструкцию:

{% for el in articles %}

<div class="alert alert-info"> <h2>{{ el.title }}</h2>

<p>{{ el.intro }}</p>

<p><b>Дата: {{ el.date.date() }}</b></p>

<a href="/posts/{{ el.id }}" class="btn btn-warn- ing">Детали</a>

</div>

{% endfor %}

Здесь в цикле по всем элементам articles выводятся title, intro и date в HTML-документ. Присутствует также ссылка типа /posts/ID для отображениядеталей. Пропишем восновномдокументеперенаправлениена данные страницы:

@app.route('/posts/<int:id>') def post_detail(id):

article = Article.query.get(id)

return render_template("post_detail.html", article=article)

Здесь в функции post_detail при помощи get() берется запись с определенным идентификатором. Она передается в файл post_detail.html. Создадим его и пропишем конструкцию для отображения:

{% block title %} {{ article.title }} {% endblock %}

{% block body %}

<div class="container mt-5"> <h1>{{ article.intro }}</h1>

49

<div class="alert alert-info"> <p>{{ article.text }}</p>

<p><b>Дата: {{ article.date.date() }}</b></p> </div>

</div>

{% endblock %}

Функции удаления и обновления

Для удаления и обновления записи добавим следующие ссылки:

<a href="/posts/{{ article.id }}/del" class= "btn btn-danger">Удалить</a>

<a href="/posts/{{ article.id }}/update" class="btn btn-success">Редактировать</a>

Пропишем в основном документе удаление записи:

@app.route('/posts/<int:id>/del') def post_delete(id):

article = Article.query.get_or_404(id)

try:

db.session.delete(article)

db.session.commit() return redirect('/posts') except:

return "При удалении возникла ошибка"

Здесь в функции post_delete при помощи get_or_404() (в случае, еслизаписьнесуществует, выдаетсяошибка404) беретсязапись с определенным идентификатором. Далее производится попытка удаления article из базы данных при помощи session.delete() и session.commit(). В случае корректной обработки происходит перенаправление, в обратном случае выводится ошибка.

Пропишем обновление записи:

@app.route('/posts/<int:id>/update', methods=['POST', 'GET'])

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]