Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Мега-Учебник Flask, Часть 4: База данных

Anna | 16.06.2014 | нет комментариев
Это вторая статья в серии, где я описываю свой навык написания веб-приложения на Python с применением микрофреймворка Flask.

Цель данного начальства — разработать достаточно функциональное приложение-микроблог, которое я за полным отсутствием оригинальности решил назвать microblog.

Содержание

Часть 1: Здравствуй, Мир! 
Часть 2: Образцы
Часть 3: Формы
Часть 4: База данных
Часть 5: Вход пользователей
Часть 6: Страница профиля и аватары
Часть 7: Unit-тестирование
Часть 8: Подписчики, контакты и друзья
Часть 9: Пагинация
Часть 10: Полнотекстовый поиск
Часть 11: Помощь e-mail
Часть 12: Реконструкция
Часть 13: Дата и время
Часть 14: I18n and L10n
Часть 15: Ajax
Часть 16: Отладка, тестирование и профилирование
Часть 17: Развертывание на Linux (даже на Raspberry Pi!)
Часть 18: Развертывание на Heroku Cloud

Короткое повторение

В предыдущей части мы сотворили нашу форму входа в комплекте с представлением и валидацией.

В этой статье мы намереваемся сделать нашу базу данных и поднять ее, Дабы мы могли записывать туда наших пользователей.

Дабы следовать этой части, ваше приложение микроблога должно быть таким, каким мы оставили его в конце предыдущей. Пожалуйста, удостоверитесь, что прилолжение установлено и работает.

Запуск Python скриптов из командной строки

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

Если вы пользователь Linux либо OS X, то скриптам необходимо дать права на исполнение:

chmod a x script.py

У скрипта есть shebang линия (Прим. перев.:В Unix, если первыми двумя байтами исполняемого файла являются “#!”, ядро обрабатывает файл как сценарий, а не как машинный код. Слово позже “!” (т.е. все до первого пробела) применяется в качестве пути к интерпретатору.), которая определяет какой интерпретатор должен быть использован. Скрипт с выданными правами на исполнение и shebang линией может быть легко запущен так:

./script.py <доводы>

На Windows, впрочем, это не сработает, и взамен этого вы обязаны передать скрипт как довод выбранному интерпретатору Python:

flaskScriptspython script.py <доводы>

Дабы избежать необходимости вводить путь к интерпретатору, вы можете добавить вашу директорию microblogflaskScripts в системный PATH, удостоверясь что он [путь к интерпретатору] написан до вашего непрерывного интерпретатора.

Отныне в этом начальстве для краткости будет применяться синтаксис Linux/OS X. Если вы пользователь Windows, то не забывайте соответствующе изменять синтаксис.

Базы данных во Flask

Для управления нашим приложением мы будем применять растяжение Flask-SQLAlchemy. Это растяжение предоставляет собой обертку для плана SQLAlchemy, тот, что является ORM либо Объектно-реляционным отображением (англ. Object-relational mapping).

ORM разрешает приложениям БД трудиться с объектами взамен таблиц либо SQL. Операции выполняются над объектами, а потом прозрачно транслируются в команды БД при помощи ORM. Реально это обозначает, что мы не будем постигать SQL в этом начальстве, а дозволим Flask-SQLAlchemy говорить на SQL за нас.

Миграции

Множество начальств, которые я видел, затрагивают создание и применение БД, но не рассматриваются надлежащим образом задачи обновления базы из-зs_rqvmk! говорит Python как выводить объекты этого класса. Мы будем применять его для отладки

Создание базы данных

Мы покончили с конфигурацией и моделью, сейчас мы готовы сделать файл с нашей базой данных. ПакетSQLAlchemy-migrate поставляется с инструментами командной строки и API для создания баз данных, которые дозволят легко обновляться в грядущем, что мы и будем делать. Я нахожу инструменты командной строки местами неудобными в применении, следственно взамен них я написал свой комплект маленьких Python скриптов, которые вызывают API миграций.

Вот скрипт, тот, что создает базу данных (файл db_create.py):

#!flask/bin/python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
from app import db
import os.path
db.create_all()
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
    api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
    api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
    api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, api.version(SQLALCHEMY_MIGRATE_REPO))

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

Дабы сделать базу данных, вам необходимо легко запустить скрипт (помните, что если вы на Windows, то команда слегка отличается):

./db_create.py

Позже ввода команды вы получите новейший файл app.db. Это пустая база данных sqlite, первоначально поддерживающая миграции. У вас также есть директория db_repository с несколькими файлами внутри. В этом месте SQLAlchemy-migrate хранит свои файлы с данными. Подмечу, что не пересоздаем репозиторий, если он теснее сделан. Это дозволит нам воссоздать базы данных из присутствующего репозитория, если потребуется.

Наша первая миграция

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

Дабы запустить миграцию я использую иной вспомогательный скрипт (файл db_migrate.py):

#!flask/bin/python
import imp
from migrate.versioning import api
from app import db
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
migration = SQLALCHEMY_MIGRATE_REPO   '/versions/%03d_migration.py' % (api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)   1)
tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec old_model in tmp_module.__dict__
script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, tmp_module.meta, db.metadata)
open(migration, "wt").write(script)
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print 'New migration saved as '   migration
print 'Current database version: '   str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

Скрипт выглядит трудным, но на самом деле он делает немножко. Метод создания миграции SQLAlchemy-migrate состоит в сопоставлении конструкции нашей базы данных (полученной из файла app.db) и конструкции нашей модели (полученной из файла models.py). Отличия между ними записываются как скрипт миграции внутри репозитория. Скрипт миграции знает как применить миграцию либо отменить ее, таким образом неизменно будет допустимо обновить либо «откатить» формат базы данных.

Пока у меня не было задач с механической генерацией миграций вышеупомянутым скриптом, я мог следить, что подчас сложно определить, легко сопоставляя ветхий и новейший формат, какие метаморфозы были сделаны. Для облегчения работы SQLAlchemy-migrate в определении изменений, я никогда не переименовываю существующие поля, ограничивая метаморфозы добавлением/удалением моделей либо полей, меняю типы сделанных полей. И я неизменно осматриваю сгенерированный скрипт миграции, Дабы убедиться в его правильности.

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

Так что давайте двинемся вперед и запишем нашу миграцию:

./db_migrate.py

И скрипт выведет:

New migration saved as db_repository/versions/001_migration.py
Current database version: 1

Сценарий показывает где был сохранен скрипт миграции, а также выводит нынешнюю версию базы данных. У пустой бд была версия 0, позже миграции с включением пользователей у нас версия 1.

Апргейд и даунгрейд базы данных

Сейчас вам может быть увлекательно отчего так значимо проходить через добавочные хлопоты в записи миграций бд.

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

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

Если у вас есть помощь миграций бд, когда вы готовы выпустить новую версию приложения на ваш продакшн сервер, то вам необходимо легко записать новую миграцию, скопировать скрипты миграции на ваш сервер и запустить примитивный скрипт, тот, что применяет ваши метаморфозы. Обновление бд может быть сделано этим маленьким Python скриптом (файл db_upgrade.py):

#!flask/bin/python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)
print 'Current database version: '   str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

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

Связи БД

Реляционные базы данных классны в хранении связей между элементами данных. Разглядим случай, в котором пользователь пишет пост в блог. У него будет запись в таблице пользователей, и пост будет добавлен в таблицу постов. Особенно результативный метод записать кто написал данный пост — связать две родные записи.

Позже того, как установлена связь между пользователем и постом, есть два типа запросов, которые нам могут потребоваться. Самый банальный, когда у вас есть пост и необходимо знать кто из пользователей его написал. Чуть больше трудный вопрос является обратным этому. Если у вас есть пользователь, то вам может потребоваться получить все написанные им записи. Flask-SQLAlchemy поможет нам с обоими типами запросов.

Расширим нашу бд для хранения постов, Дабы мы могли увидеть связи в действии. Для этого мы возвратимся к нашему инструменту дизайна бд и сделаем таблицу записей:

В нашей таблице записей будут: id, текст записи и дата. Ничего нового. Но поле user_id заслуживает объяснения.

Мы решили, что хотим связать пользователей и записи, которые они пишут. Метод осуществления — добавление поля в пост, которое содержит id пользователя, написавшего его. Данный id именуется внешний ключ (англ. foreign key). Наш инструмент проектирования бд показывает внешние ключи как связь между ключем и полем id, на которое он ссылается. Данный вид связи именуется один-ко-многим (англ. one-to-many), один пользователь пишет много постов.

Давайте изменим нашу модель, Дабы отразить эти метаморфозы (app/models.py):

from app import db

ROLE_USER = 0
ROLE_ADMIN = 1

class User(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    nickname = db.Column(db.String(64), unique = True)
    email = db.Column(db.String(120), unique = True)
    role = db.Column(db.SmallInteger, default = ROLE_USER)
    posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')

    def __repr__(self):
        return '<User %r>' % (self.nickname)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post %r>' % (self.body)

Мы добавили класс Post, тот, что будет представлять записи в блоге, написанные пользователями. Полеuser_id в классе Post будет инициализировано как внешний ключ, так что Flask-SQLAlchemy знает, что это поле будет связано с пользователем.

Подметьте, что мы также добавил, timestamp=datetime.datetime.utcnow(), author=u) >>> db.session.add(p) >>> db.session.commit()

Здесь мы устанавливаем нашу дату во временной зоне UTC. Все временные метки, хранящиеся в нашей бд, будут в UTC. У нас могут быть пользователи со каждого мира и необходимо применять цельные еденицы времени. В грядущем начальство покажет как отображать время в пользовательском часовом поясе.

Вы, допустимо, подметили, что мы не установили поле user_id в классе Post. Взамен этого мы бережем объект User внутри нашего поля author. Это виртуальное поле было добавлено Flask-SQLAlchemy для помощи со связями, мы определили имя этого поля в доводе backref в db.relationship нашей модели. С этой информацией слой ORM будет знать как заполнять для нас user_id.

Для заключения этой сессии, давайте посмотрим на еще несколько запросов к базе данных, что мы можем сделать:

# получаем все записи пользователя
>>> u = models.User.query.get(1)
>>> print u
<User u'john'>
>>> posts = u.posts.all()
>>> print posts
[<Post u'my first post!'>]

# получаем автора всякой записи
>>> for p in posts:
...     print p.id,p.author.nickname,p.body
...
1 john my first post!

# пользователь без записей
>>> u = models.User.query.get(2)
>>> print u
<User u'susan'>
>>> print u.posts.all()
[]

# получаем всех пользователей в обратном алфавитном порядке
>>> print models.User.query.order_by('nickname desc').all()
[<User u'susan'>, <User u'john'>]
>>>

Документация Flask-SQLAlchemy — лучшее место для постижения многих опций, доступных для запросов к бд.

Перед тем как завершить, давайте удалим тестовых пользователей и сделанные записи, Дабы начать с чистой бд в дальнейшей главе:

>>> users = models.User.query.all()
>>> for u in users:
...     db.session.delete(u)
...
>>> posts = models.Post.query.all()
>>> for p in posts:
...     db.session.delete(p)
...
>>> db.session.commit()
>>>

Завершение

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

Между тем, если вы не пишете приложение совместно с нами, то можете скачать его в нынешней версии:
microblog-0.4.zip

Обратите внимание, я не включил базу данных в zip-архив выше, но репозиторий с миграциями там. Дабы сделать новую бд легко используйте db_create.py, после этого db_upgrade.py, для обновления бд в последнюю ревизию.

Верю увидимся!

Мигель.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB