Turbogears - Краткое руководство
Что такое веб-платформа?
Web Application Framework или просто Web Framework представляет собой набор библиотек и модулей, который позволяет разработчику веб-приложений писать приложения, не беспокоясь о деталях низкого уровня, таких как протоколы, управление потоками и т. Д.
Что такое TurboGears?
TurboGears - это среда веб-приложений, написанная на Python. Первоначально созданная Кевином Дангуром в 2005 году, последняя версия TurboGears (версия 2.3.7) управляется группой разработчиков во главе с Марком Раммом и Флораном Эйдом.
TurboGears следует парадигме модель-представление-контроллер, как и большинство современных веб-фреймворков, таких как Rails, Django, Struts и т. Д.
Контроллер представления модели
MVC - это шаблон проектирования программного обеспечения для разработки веб-приложений. Шаблон Model View Controller состоит из трех частей:
Model - Самый нижний уровень шаблона отвечает за поддержание данных.
View - Он отвечает за отображение всех или части данных для пользователя.
Controller - Программный код, который контролирует взаимодействие между моделью и представлением.
MVC популярен, поскольку он изолирует логику приложения от уровня пользовательского интерфейса и поддерживает разделение задач. Здесь Контроллер получает все запросы для приложения, а затем работает с моделью, чтобы подготовить любые данные, необходимые для представления. Затем представление использует данные, подготовленные контроллером, для генерации окончательного презентабельного ответа. Абстракция MVC может быть графически представлена следующим образом:
Модель
Модель отвечает за управление данными приложения. Он отвечает на запрос из представления, а также отвечает на инструкции контроллера по обновлению.
Вид
Представление данных в определенном формате, вызванное решением контроллера представить данные. Это системы шаблонов на основе сценариев, которые очень легко интегрировать с технологией AJAX.
Контроллер
Контроллер отвечает за реакцию на ввод данных пользователем и выполнение взаимодействий с объектами модели данных. Контроллер получает входные данные, он проверяет их, а затем выполняет бизнес-операцию, которая изменяет состояние модели данных.
TurboGears построен на основе ряда библиотек и инструментов. Эти инструменты менялись между различными версиями TurboGears. Компоненты текущей версии (2.3.7) перечислены ниже.
SQLAlchemy
Это набор SQL с открытым исходным кодом, который обеспечивает сопоставление объектных отношений (ORM) для кода Python.
Генши
Этот шаблонизатор используется для создания внешнего интерфейса приложений TG. Система веб-шаблонов объединяет шаблон с определенным источником данных для отображения динамических веб-страниц.
ToscaWidgets
Это библиотека виджетов для создания HTML-форм с элементами управления на стороне сервера. Tosca также действует как промежуточное ПО для связи с виджетами и инструментами JavaScript.
Коробка передач
Он предоставляет набор команд для управления проектами и серверными приложениями TurboGears. Приложения TurboGears можно развернуть на любом веб-сервере, совместимом с WSGI.
Интерфейс шлюза веб-сервера (WSGI) был принят в качестве стандарта для разработки веб-приложений Python. WSGI - это спецификация универсального интерфейса между веб-сервером и веб-приложениями. Пакет wsgiref - это эталонная реализация WSGI. Он используется для добавления поддержки WSGI в веб-платформу Web TurboGears. Модуль simple_server в этом пакете реализует простой HTTP-сервер, обслуживающий приложения WSGI. Мы будем использовать его для тестирования приложений, разработанных в этом руководстве.
Предпосылка
Python 2.6 или выше. Более ранние версии TurboGears несовместимы с Python 3.X. Последняя версия утверждает, что хорошо работает с Python 3.X. Однако официальная документация TurboGears по-прежнему основана на среде Python 2.7.
Следующая команда installs virtualenv -
pip install virtualenv
Эта команда требует administratorпривилегии. Добавитьsudo before pipв Linux / Mac OS. Если вы работаете в Windows, войдите в систему как администратор. В Ubuntu virtualenv можно установить с помощью диспетчера пакетов.
Sudo apt-get install virtualenv
После установки новая виртуальная среда создается в папке.
mkdir newproj
cd newproj
virtualenv venv
Чтобы активировать соответствующую среду, на Linux/OS X
venv/bin/activate
на Windows
venv\scripts\activate
Теперь мы готовы install TurboGearsв этой среде. Минимальная установка TurboGears выполняется следующей командой -
pip install TurboGears2
Вышеупомянутую команду можно запустить напрямую без виртуальной среды для общесистемной установки.
Чтобы установить TurboGears вместе со средствами разработки, используйте следующую команду -
pip install tg.devtools
TurboGears имеет минимальный режим, который позволяет быстро создавать однофайловые приложения. Простые примеры и сервисы можно быстро построить с минимальным набором зависимостей.
Класс приложения в приложении TG наследуется от TGControllerкласс. Методы этого класса доступны для доступа@expose декоратор из tgмодуль. В нашем первом приложенииindex()отображается как корень нашего приложения. Класс TGController также необходимо импортировать изtg модуль.
from tg import expose, TGController
class MyController(TGController):
@expose()
def index(self):
return 'Hello World turbogears'
Затем установите конфигурацию приложения и объявите объект приложения. AppConfig Здесь конструктор класса принимает два параметра - минимальный атрибут, для которого установлено значение true, и класс контроллера.
config = AppConfig(minimal = True, root_controller = RootController())
application = config.make_wsgi_app()
В make_wsgi_app() здесь функция создает объект приложения.
Теперь для обслуживания этого приложения нам нужно запустить HTTP-сервер. Как упоминалось ранее, мы будем использоватьsimple_server модуль в wsgirefпакет для настройки и запуска. Этот модуль имеетmake_server() метод, который требует в качестве аргументов номер порта и объект приложения.
from wsgiref.simple_server import make_server
server = make_server('', 8080, application)
server.serve_forever()
Это означает, что наше приложение будет обслуживаться на порту 8080 localhost.
Ниже приведен полный код нашего первого приложения TurboGears:
app.py
from wsgiref.simple_server import make_server
from tg import expose, TGController, AppConfig
class MyController(TGController):
@expose()
def index(self):
return 'Hello World TurboGears'
config = AppConfig(minimal = True, root_controller = MyController())
application = config.make_wsgi_app()
print "Serving on port 8080..."
server = make_server('', 8080, application)
server.serve_forever()
Запустите приведенный выше сценарий из оболочки Python.
Python app.py
Войти http://localhost:8080 в адресной строке браузера, чтобы просмотреть сообщение «Hello World TurboGears».
В tg.devtoolsTurboGears содержит коробку передач. Это набор команд, которые полезны для управления более сложными проектами TG. Полностековые проекты можно быстро создать с помощью следующей команды Gearbox -
gearbox quickstart HelloWorld
Это создаст проект под названием HelloWorld.
Проект TurboGears содержит следующие каталоги -
Config - Откуда зависит установка и настройка проекта
Controllers - Все контроллеры проекта, логика веб-приложения
i018n - Файлы перевода для поддерживаемых языков
Lib - Служебные функции и классы Python
Model - Модели базы данных
Public Static Files - CSS, JavaScript и изображения
Templates - Шаблоны, предоставляемые нашими контроллерами.
Tests - Выполнен набор тестов.
Websetup - Функции для выполнения при настройке приложения.
Как установить проект
Теперь этот проект необходимо установить. Аsetup.pyуже присутствует в базовом каталоге проекта. При выполнении этого скрипта устанавливаются зависимости проекта.
Python setup.py develop
По умолчанию во время настройки проекта устанавливаются следующие зависимости:
- Beaker
- Genshi
- zope.sqlalchemy
- sqlalchemy
- alembic
- repoze.who
- tw2.forms
- tgext.admin ≥ 0.6.1
- WebHelpers2
- babel
После установки начните обслуживать проект на сервере разработки, выполнив следующую команду в оболочке -
Gearbox serve –reload –debug
Следуйте указанной выше команде, чтобы показать готовый пример проекта. открытоhttp://localhost:8080в браузере. Этот готовый пример приложения дает краткое введение в сам фреймворк TurboGears.
В этом проекте Hello контроллер по умолчанию создается в каталоге контроллеров как Hello/hello/controllers.root.py. Разрешите намmodify root.py со следующим кодом -
from hello.lib.base import BaseController
from tg import expose, flash
class RootController(BaseController):
movie = MovieController()
@expose()
def index(self):
return "<h1>Hello World</h1>"
@expose()
def _default(self, *args, **kw):
return "This page is not ready"
Когда базовое рабочее приложение готово, в класс контроллера можно добавить больше представлений. вMycontroller класс выше, новый метод sayHello()добавлен. В@expose() декоратор прикрепляет /sayHelloURL к нему. Эта функция предназначена для приема имени в качестве параметра URL-адреса.
После запуска сервера через команду 'gearbox serve', http://localhost:8080. Сообщение Hello World будет отображаться в браузере, даже если будут введены следующие URL-адреса:
http://localhost:8080/
http://localhost:8080/index
Все эти URL-адреса сопоставлены RootController.index()метод. В этом классе также есть_default()метод, который будет вызываться всякий раз, когда URL-адрес не сопоставлен с какой-либо конкретной функцией. Ответ на URL-адрес сопоставляется функции декоратором @expose ().
Можно отправить параметр открытой функции из URL-адреса. Следующая функция считывает параметр имени из URL-адреса.
@expose()
def sayHello(self, name):
return '<h3>Hello %s</h3>' %name
Следующий вывод будет виден в браузере как ответ на URL-адрес - http://localhost:8080/?name=MVL
Hello MVL
TurboGears автоматически сопоставляет параметры URL-адреса с аргументами функции. Наш класс RootController унаследован от BaseController. Это определяется какbase.py в lib folder приложения.
Его код следующий -
from tg import TGController, tmpl_context
from tg import request
__all__ = ['BaseController']
def __call__(self, environ, context):
tmpl_context.identity = request.identity
return TGController.__call__(self, environ, context)
TGController.__call__ отправляет в метод контроллера, на который направлен запрос.
Событие, хотя содержимое HTML может быть возвращено в браузер, для более продвинутого вывода всегда предпочтительнее использовать механизм шаблонов. В полномасштабном проекте, запущенном с помощью gearbox, Genshi включен в качестве средства визуализации шаблонов по умолчанию. Однако в минимальном приложении Genshi (или любой другой шаблонизатор, например jinja) должен быть установлен и включен. Механизм шаблонов Genshi позволяет писать шаблоны в чистом xhtml и проверять их, чтобы обнаруживать проблемы во время компиляции и предотвращать обслуживание сломанных страниц.
Шаблоны обозначены пунктирной нотацией. В нашем проекте Hello предоставляется каталог шаблонов для хранения шаблонов веб-страниц. Следовательноsample.html будет называться hello.templates.sample(расширение не упоминается). TurboGears отображает этот шаблон через декоратор экспонирования, чтобы связать с ним метод контроллера с помощьюtg.render_template() функция.
Открытая функция контроллера возвращает объект словаря Python. Этот объект словаря, в свою очередь, передается в связанный шаблон. Заполнители в шаблоне заполняются словарными значениями.
Для начала давайте отобразим веб-страницу с помощью простого html-скрипта. Открытый контроллер возвращаетnull dictionary object поскольку мы не намерены отправлять какие-либо данные для анализа внутри HTML-скрипта.
Как создать образец HTML
Наши sample.htmlприведен ниже. Убедитесь, что он хранится в каталоге шаблонов проекта.
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
</body>
</html>
Добавить sample() функционировать в root.py и выставить через него файл sample.html.
@expose("hello.templates.sample")
def sample(self):
return {}
Следующий результат будет отображаться в браузере, когда URL http://localhost:8080/sample вводится после запуска веб-сервера.
Как упоминалось выше, объект словаря отправляется как набор параметров в шаблон Genshi. Этот шаблон содержит "заполнители", которые динамически заполняются параметрами, полученными от контроллера.
Давайте изменим sample() функция для отправки объекта словаря в образец шаблона.
@expose("hello.templates.sample")
def sample(self,name):
mydata = {'person':name}
return mydata
Создайте sample.html в папке шаблонов (templates\sample.html)
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, my name is ${person}!.</h2>
</body>
</html>
В приведенном выше HTML-коде ${person}заполнитель. Войтиhttp://localhost:8080/sample?name=MVLкак URL-адрес в браузере. Этот URL сопоставлен сsample()в нашем корневом контроллере. Он возвращает объект словаря. Это выбирается связанной страницей шаблона sample.html в каталоге шаблонов. Затем $ {person} заменяется на MVL на веб-странице.
Также можно получить доступ к данным HTML-формы в функции контроллера. HTML-форма используется для отправки данных формы.
Протокол Http - это основа передачи данных во всемирной паутине. В этом протоколе определены различные методы получения данных с указанного URL. В следующей таблице приведены различные методы http:
Sr.No. | Методы и описание HTTP |
---|---|
1 | GET Отправляет данные на сервер в незашифрованном виде. Самый распространенный метод. |
2 | HEAD То же, что GET, но без тела ответа |
3 | POST Используется для отправки данных HTML-формы на сервер. Данные, полученные методом POST, сервером не кэшируются. |
4 | PUT Заменяет все текущие представления целевого ресурса загруженным контентом. |
5 | DELETE Удаляет все текущие представления целевого ресурса, заданные URL-адресом |
Создание HTML-формы
Давайте создадим HTML-форму и отправим данные формы по URL-адресу. Сохраните следующий скрипт как login.html
<html>
<body>
<form action = "http://localhost:8080/login" method = "get">
<p>Enter Name:</p>
<p><input type = "text" name = "nm" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
Данные, введенные в эту форму, должны быть отправлены в ‘/login’ URL. Теперь создайте функцию контроллераloginpage() и откройте для него указанную выше html-страницу.
@expose("hello.templates.login")
def loginpage(self):
return {}
Чтобы получить данные формы, укажите login()контроллер, который имеет атрибуты формы в качестве параметров. Вот‘nm’ - имя поля ввода текста в форме входа в систему, то же самое используется в качестве параметра функции login ().
@expose("hello.templates.sample")
def login(self, nm):
name = nm
return {'person':name}
Как видно, данные, полученные из формы входа, отправляются в шаблон sample.html (использованный ранее). Он анализируетсяGenshi template engine чтобы сгенерировать следующий вывод -
Метод POST
Когда HTML-форма использует метод POST для отправки данных в URL-адрес в атрибуте действия, данные формы не отображаются в URL-адресе. Закодированные данные поступают вdictаргумент функцией контроллера. **kw Аргумент ниже - это объект словаря, содержащий данные.
HTML-форма содержит два текстовых поля ввода.
<html>
<body>
<form action = "http://localhost:8080/marks" method = "post">
<p>Marks in Physics:</p>
<p><input type = "text" name = "phy" /></p>
<p>Marks in Maths:</p>
<p><input type = "text" name = "maths" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
В marks() Контроллер получает данные формы и отправляет их sample.htmlшаблон. Код дляroot.py выглядит следующим образом -
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose("hello.templates.marks")
def marksform(self):
return {}
@expose("hello.templates.sample")
def marks(self, **kw):
phy = kw['phy']
maths = kw['maths']
ttl = int(phy)+int(maths)
mydata = {'phy':phy, 'maths':maths, 'total':ttl}
return mydata
Наконец, шаблон sample.html выглядит следующим образом:
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
<h3>Marks in Physics: ${phy}.</h3>
<h3>Marks in Maths: ${maths}.</h3> <h3>Total Marks: ${total}</h3>
</body>
</html>
Запустите сервер (если он еще не запущен)
Gearbox server –reload –debug
Войти http://localhost::8080/marksform в браузере
В sample.html отобразит следующий вывод -
Genshi - это язык шаблонов на основе XML. Это похоже наKid, который раньше был механизмом шаблонов для более ранних версий TurboGears. Генши и Кид вдохновлены другими известными языками шаблонов, такими какHSLT, TAL и PHP.
Шаблон Genshi состоит из директив обработки. Эти Директивы являются элементами и атрибутами в шаблоне. Директивы Genshi определены в пространстве именhttp://genshi.edgewall.org/. Следовательно, это пространство имен необходимо объявить в корневом элементе шаблона.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
...
</html>
Вышеупомянутое объявление означает, что пространство имен по умолчанию установлено на XHTML, а директивы Genshi имеют префикс py.
Директивы Генши
В Genshi определен ряд директив. В следующем списке перечислены директивы Генши -
- py:if
- py:choose
- py:for
- py:def
- py:match
- py:with
- py:replace
- py:content
- py:attrs
- py:strip
Условные разделы
Genshi предоставляет две директивы для условного рендеринга контента - py: if и py: choose.
ру: если
Содержимое элемента этой директивы будет отображаться, только если выражение в if clauseоценивается как истина. Предполагая, что данные в контексте шаблона{‘foo’:True, ‘bar’:’Hello’}, следующая директива -
<div>
<b py:if = "foo">${bar}</b>
</div>
приведет к
Hello
Однако этот вывод не будет отображаться, если ‘foo’ is set to False.
Эта директива также может использоваться как элемент. В этом случае<py:if> должны быть закрыты соответствующими </py:if>
<div>
<py:if test = "foo">
<b>${bar}</b>
</py:if>
</div>
ру: выбрать
Возможна расширенная условная обработка с использованием py:choose в комбинации с py:when и py:otherwiseдирективы. Эта функция похожа наswitch – case построить в C/C++.
Выражение в py:choose директива проверяется с разными значениями, идентифицированными с py:whenальтернативы и соответствующее содержимое будут отображены. Альтернатива по умолчанию может быть предоставлена в видеpy:otherwise директива.
<div py:choose = "foo”>
<span py:when = "0">0</span>
<span py:when = "1">1</span>
<span py:otherwise = "">2</span>
</div>
В следующем примере показано использование py:choose и py:whenдирективы. HTML-форма отправляет данные в / отмечает URL. Вmarks() функция перенаправляет метки и результаты в виде объекта словаря на total.htmlшаблон. Условное отображениеresult Pass/Fail достигается за счет использования py:choose и py:when директивы.
HTML-скрипт ввода меток (marks.html) выглядит следующим образом -
<html>
<body>
<form action = "http://localhost:8080/marks" method = "post">
<p>Marks in Physics:</p>
<p><input type = "text" name = "phy" /></p>
<p>Marks in Maths:</p>
<p><input type = "text" name = "maths" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
Полный код root.pyкак следует. Вmarks() контроллер отправляет отметки и результат в total.html шаблон -
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose("hello.templates.marks")
def marksform(self):
return {}
@expose("hello.templates.total")
def marks(self, **kw):
phy = kw['phy']
maths = kw['maths']
ttl = int(phy)+int(maths)
avg = ttl/2
if avg ≥ 50:
mydata = {'phy':phy, 'maths':maths, 'total':ttl, 'result':2}
else:
mydata = {'phy':phy, 'maths':maths, 'total':ttl,'result':1}
return mydata
В total.html в папке шаблонов получает данные словаря и анализирует их в выводе html условно следующим образом:
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
<h3>Marks in Physics: ${phy}.</h3> <h3>Marks in Maths: ${maths}.</h3>
<h3>Total Marks: ${total}</h3>
<div py:choose = "result">
<span py:when = "1"><h2>Result: Fail</h2></span>
<span py:when = "2"><h2>Result: Pass</h2></span>
</div>
</body>
</html>
Запустите сервер (если он еще не запущен)
Gearbox server –reload –debug
Войти http://localhost::8080/marksform в браузере -
В total.html отобразит следующий вывод -
py: для
Элемент в директиве py: for повторяется для каждого элемента в итерации, обычно это объект списка Python. Еслиitems = [1,2,3] присутствует в контексте шаблона, его можно повторить, выполнив следующую директиву py: for -
<ul>
<li py:for = "item in items">${item}</li>
</ul>
Будет отображен следующий вывод -
1
2
3
В следующем примере показаны данные HTML-формы, отображаемые в шаблоне total.html с использованием директивы py: for, также можно использовать следующим образом:
<py:for each = "item in items">
<li>${item}</li>
</py:for>
Скрипт HTML-формы
<html>
<body>
<form action = "http://localhost:8080/loop" method="post">
<p>Marks in Physics:</p>
<p><input type = "text" name = "phy" /></p>
<p>Marks in Chemistry:</p>
<p><input type = "text" name = "che" /></p>
<p>Marks in Maths:</p>
<p><input type = "text" name = "maths" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
В loop() Контроллер считывает данные формы и отправляет их в total.template в виде объекта списка.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose("hello.templates.marks")
def marksform(self):
return {}
@expose("hello.templates.temp")
def loop(self, **kw):
phy = kw['phy']
maths = kw['maths']
che = kw['che']
l1 = []
l1.append(phy)
l1.append(che)
l1.append(maths)
return ({'subjects':['physics', 'Chemistry', 'Mathematics'], 'marks':l1})
В шаблоне temp.html используется цикл py: for для отображения содержимого объекта dict в виде таблицы.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/" lang = "en">
<body>
<b>Marks Statement</b>
<table border = '1'>
<thead>
<py:for each = "key in subjects"><th>${key}</th></py:for>
</thead>
<tr>
<py:for each = "key in marks"><td>${key}</td></py:for>
</tr>
</table>
</body>
</html>
Запустите сервер (если он еще не запущен)
gearbox server –reload –debug
Войти http://localhost::8080/marksform в браузере.
Следующий вывод будет отображаться в браузере после отправки формы выше.
py: def
Эта директива используется для создания макроса. Макрос - это многократно используемый фрагмент кода шаблона. Как и функция Python, у нее есть имя и, при желании, параметры. Вывод этого макроса можно вставить в любое место шаблона.
Директива py: def следует следующему синтаксису -
<p py:def = "greeting(name)">
Hello, ${name}!
</p>
Этот макрос может быть отображен со значением переменной для параметра name.
${greeting('world')} ${greeting('everybody)}
Эту директиву также можно использовать с другой версией синтаксиса следующим образом:
<py:def function = "greeting(name)">
<p>Hello, ${name}! </p>
</py:def>
В следующем примере macro() контроллер в root.py отправляет dict объект с двумя ключами name1 и name2 к шаблону macro.html.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.macro')
def macro(self):
return {'name1':'TutorialPoint', 'name2':'TurboGears'}
Этот шаблон macro.html содержит определение макроса, называемого приветствием. Он используется для генерации приветственного сообщения для данных, полученных от контроллера.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<body>
<h2>py:def example</h2>
<div>
<div py:def = "greeting(name)">
Hello, Welcome to ${name}!
</div>
<b>
${greeting(name1)} ${greeting(name2)}
</b>
</div>
</body>
</html>
Запустите сервер с помощью коробки передач
gearbox serve –reload –debug
Вызовите контроллер macro (), введя следующий URL-адрес в браузере -
http://localhost:8080/macro
Следующий вывод будет отображаться в браузере -
py: с
Эта директива позволяет назначать выражения локальным переменным. Эти локальные переменные делают выражение внутри менее подробным и более эффективным.
Предполагая, что x = 50 задано в данных контекста для шаблона, далее будет директива py: with -
<div>
<span py:with = "y = 50; z = x+y">$x $y $z</span>
</div>
Это приведет к следующему выводу -
50 50 100
Также доступна альтернативная версия для директивы py: with -
<div>
<py:with = "y = 50; z = x+y">$x $y $z</py:with>
</div>
В следующем примере контроллер macro () возвращает объект dict с ключами name, phy и maths.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.macro')
def macro(self):
return {'name':'XYZ', 'phy':60, 'maths':70}
Шаблон macro.html добавляет значения ключей phy и maths с помощью директивы py: with.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<body>
<h2>py:with example</h2>
<h3>Marks Statement for : ${name}!</h3> <b>Phy: $phy Maths: $maths <span py:with = "ttl = phy+maths">Total: $ttl</span>
</b>
</body>
</html>
Браузер отобразит следующий вывод в ответ на URL-адрес http://localhost:8080/macro
Директивы по манипулированию структурой
В py:attrs Директива добавляет, изменяет или удаляет атрибуты элемента.
<ul>
<li py:attrs = "foo">Bar</li>
</ul>
Если foo = {‘class’:’collapse’} присутствует в контексте шаблона, который будет отображать приведенный выше фрагмент.
<ul>
<li class = "collapse">Bar</li>
</ul>
В py:content Директива заменяет любой вложенный контент результатом вычисления выражения -
<ul>
<li py:content = "bar">Hello</li>
</ul>
Если в данных контекста bar = 'Bye', это приведет к
<ul>
<li>Bye</li>
</ul>
В py:replace Директива заменяет сам элемент результатом вычисления выражения -
<div>
<span py:replace = "bar">Hello</span>
</div>
Если в данных контекста bar = 'Bye', это приведет к
<div>
Bye
</div>
Содержимое другого XML-документа (особенно HTML-документа) можно включить с помощью тегов включения в текущий документ. Чтобы включить такое включение, пространство имен XInclude должно быть объявлено в корневом элементе документа HTML.
<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:xi = "http://www.w3.org/2001/XInclude >
Приведенное выше объявление указывает, что директива include содержит ‘xi’приставка. Чтобы добавить содержимое другой html-страницы в текущий документ, используйте директиву xi: include следующим образом:
<xi:include href = "somepage.html" />
В следующем примере root.py содержит контроллер include (), который предоставляет include.html.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.include')
def include(self):
return {}
HTML-код заголовка и нижнего колонтитула
В include.html объявляется пространство имен include и добавляется содержимое heading.html и footer.html. Вот HTML-сценарий templates \ include.html -
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<xi:include href = "heading.html" />
<h2>main content </h2>
<xi:include href = "footer.html" />
</body>
</html>
Вот код templates \ heading.html -
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h1>This is page Header</h1>
</body>
</html>
Ниже приведены шаблоны \ footer.html
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h3>This is page footer</h3>
</body>
</html>
Запустите разработку с помощью коробки передач и введите http://localhost:8080/includeв браузере. Результат рендеринга будет таким, как показано ниже -
Таким образом может быть достигнута модульная конструкция видов. Если ресурс, указанный в директиве xi: include, недоступен, возникнет ошибка. В таком случае можно загрузить альтернативный ресурс с помощью xi: fallback.
<xi:include href = “main.html”>
<xi:fallback href = ”default.html”/>
</xi.include>
Включение контента можно сделать динамическим как атрибут href, который может содержать выражения.
Добавьте следующий контроллер в root.py.
@expose('hello.templates.ref-include')
def refinclude(self):
return {'pages':['heading','main','footer']}
Сохраните следующий код как ref-include.html в папке шаблонов.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<xi:include href = "${name}.html" py:for = "name in pages" />
</body>
</html>
Перед запуском сервера убедитесь, что в папке шаблонов есть заголовки.html, main.html и footer.html. Войтиhttp://localhost:8082/refinclude в браузере, чтобы получить следующий результат
В @expose()декоратор по умолчанию отображает html-контент. Однако это может быть установлено наjson content type. TurboGears поддерживает рендеринг json черезtg.jsonify.JSONEncoder (**kwargs)класс. Чтобы отобразить данные json, просто передайте json в качестве типа содержимого для предоставления декоратора.
@expose('json')
def jsondata(self, **kwargs):
return dict(hello = 'World')
Если URL-адрес '/ jsondata' введен в браузере, он ответит, показывая -
{"hello": "World"}
jsonp рендеринг
jsonp означает json с заполнением. Он работает так же, как вывод json, за исключением того факта, что он предоставляет ответ приложения / javascript с вызовом функции javascript, предоставляя все значения, возвращаемые контроллером в качестве аргументов функции.
Чтобы включить рендеринг jsonp, вы должны сначала добавить его в список необходимых движков внутри вашего приложения - config/app_cfg.py -
base_config.renderers.append('jsonp')
Напишите свой декоратор экспонирования следующим образом -
@expose('json')
@expose('jsonp')
def jsonpdata (self, **kwargs):
return dict(hello = 'World')
При доступе к / jsonpdata? Callback = callme вы должны увидеть -
callme({"hello": "World"});
Иногда веб-приложению может потребоваться структура URL-адреса, имеющая более одного уровня. TurboGears может просматривать иерархию объектов, чтобы найти подходящий метод, способный обработать ваш запрос.
Проект, «начатый» с помощью gearbox, имеет класс BaseController в папке проекта lib. Он доступен как «Hello / hello / lib / base.py». Он служит базовым классом для всех субконтроллеров. Чтобы добавить подуровень URL-адреса в приложение, создайте подкласс под названием BlogController, производный от BaseController.
Этот BlogController имеет две функции контроллера: index () и post (). Оба предназначены для предоставления по одному шаблону, blog.html и post.html.
Note - Эти шаблоны помещаются в подпапку - templates / blog
class BlogController(BaseController):
@expose('hello.templates.blog.blog')
def index(self):
return {}
@expose('hello.templates.blog.post')
def post(self):
from datetime import date
now = date.today().strftime("%d-%m-%y")
return {'date':now}
Теперь объявите объект этого класса в классе RootController (в root.py) следующим образом:
class RootController(BaseController):
blog = BlogController()
Другие функции контроллера для URL верхнего уровня будут присутствовать в этом классе, как и раньше.
Когда URL http://localhost:8080/blog/введен, он будет сопоставлен с функцией контроллера index () внутри класса BlogController. Так же,http://localhost:8080/blog/post вызовет функцию post ().
Код для blog.html и post.html следующий:
Blog.html
<html>
<body>
<h2>My Blog</h2>
</body>
</html>
post.html
<html>
<body>
<h2>My new post dated $date</h2>
</body>
</html>
Когда URL http://localhost:8080/blog/ введен, он выдаст следующий результат -
Когда URL http://localhost:8080/blog/post введен, он выдаст следующий результат -
Одним из наиболее важных аспектов любого веб-приложения является представление пользовательского интерфейса пользователю. HTML предоставляет тег <form>, который используется для разработки интерфейса. Элементы формы, такие как ввод текста, радио, выбор и т. Д., Могут использоваться соответствующим образом. Данные, введенные пользователем, отправляются в виде сообщения HTTP-запроса на серверный сценарий с помощью метода GET или POST.
Сценарий на стороне сервера должен воссоздавать элементы формы из данных HTTP-запроса. Таким образом, в этом случае элементы формы должны быть определены дважды - один раз в HTML и еще раз в сценарии на стороне сервера.
Еще один недостаток использования HTML-формы состоит в том, что сложно (если не невозможно) отображать элементы формы динамически. Сам HTML не дает возможности проверить ввод данных пользователем.
ToscaWidgets2
TurboGears полагается на ToscaWidgets2, гибкую библиотеку визуализации и проверки форм. Используя ToscaWidgets, мы можем определять поля формы в нашем скрипте Python и отображать их с помощью шаблона HTML. Также можно применить проверку к полю tw2.
Библиотека ToscaWidgets - это набор многих модулей. Некоторые важные модули перечислены ниже -
tw2.core- Обеспечивает базовую функциональность. Виджеты в этом модуле не предназначены для конечного пользователя.
tw2.forms- Это базовая библиотека форм. Он содержит виджеты для полей, наборов полей и форм.
tw2.dynforms - Содержит функциональность динамических форм.
tw2.sqla - Это интерфейс для базы данных SQLAlchemy.
tw2.forms
Он содержит класс Form, который действует как основа для настраиваемых форм. Существует класс TableForm, который полезен при отображении полей в таблице с двумя столбцами. ListForm представляет свои поля в виде неупорядоченного списка.
Sr.No. | Поля и описание |
---|---|
1 | TextField Однострочное поле ввода текста |
2 | TextArea Поле ввода многострочного текста |
3 | CheckBox Представляет проверяемый прямоугольный ящик с этикеткой |
4 | CheckBoxList Флажки группы pf с множественным выбором |
5 | RadioButton Кнопка переключения для выбора / отмены выбора |
6 | RadioButtonList Группа взаимоисключающих радиокнопок |
7 | PasswordField Подобно текстовому полю, но клавиши ввода не отображаются |
8 | CalendarDatePicker Позволяет пользователю выбрать дату |
9 | SubmitButton Кнопка для отправки формы |
10 | ImageButton Нажимаемая кнопка с изображением сверху |
11 | SingleSelectField Позволяет выбрать один элемент из списка |
12 | MultipleSelectField Позволяет выбрать несколько элементов из списка |
13 | FileField Поле для загрузки файла |
14 | EmailField Поле ввода электронной почты |
15 | URLField Поле ввода для ввода URL |
16 | NumberField Число счетчиков |
17 | RangeField Ползунок числа |
В следующем примере создается форма, использующая некоторые из этих виджетов. Хотя большинство этих виджетов определены в tw2.forms, CalendarDateField определен в модуле tw2.Dynforms. Следовательно, оба этих модуля вместе с tw2.core импортируются в начале -
import tw2.core as twc
import tw2.forms as twf
import tw2.dynforms as twd
Форма ToscaWidgets - это класс, производный от tw2.forms.formбазовый класс. Необходимые виджеты размещаются внутри объекта Layout. В этом примереTableLayoutиспользуется. Виджеты отображаются в виде таблицы из двух столбцов. В первом столбце отображается заголовок, а во втором столбце - поле ввода или выбора.
Объект TextField создается с использованием следующего конструктора -
twf.TextField(size, value = None)
Если не упомянуто, объект TextField принимает размер по умолчанию и изначально пуст. При объявлении объекта TextArea можно указать количество строк и столбцов.
twf.TextArea("",rows = 5, cols = 30)
Объект NumberField - это текстовое поле, которое может принимать только цифры. Стрелки вверх и вниз создаются на правой границе, чтобы увеличивать или уменьшать число внутри нее. Начальное значение также можно указать в качестве аргумента в конструкторе.
twf.NumberField(value)
Справа от поля CalendarDatePicker отображается кнопка календаря. При нажатии всплывает селектор даты. Пользователь может вручную ввести дату в поле или выбрать дату в селекторе даты.
twd.CalendarDatePicker()
Объект EmailField представляет собой TextField, но текст в нем должен быть в формате электронной почты.
EmailID = twf.EmailField()
Следующая форма также имеет RadioButtonList. Конструктор этого класса содержит объект List как значение параметра options. Будет отображен переключатель для каждой опции. Выбор по умолчанию определяется параметром значения.
twf.RadioButtonList(options = ["option1","option2"],value = option1)
CheckBoxList отображает флажки для каждого параметра в списке.
twf.CheckBoxList(options = [option1, option2, option3])
Выпадающий список в этой библиотеке ToscaWidgets называется полем SingleSelect. Элементы объекта List, соответствующие параметру options, образуют раскрывающийся список. Видимый заголовок устанавливается как значение параметра prompt_text.
twf.SingleSelectField(prompt_text = 'text', options=['item1', 'item2', 'item3'])
По умолчанию в форме отображается кнопка «Отправить» с надписью «сохранить». Чтобы отобразить другой заголовок, создайте объект SubmitButton и укажите его как параметр значения.
twf.SubmitButton(value = 'Submit')
Форма отправляется по URL-адресу, который указан как значение параметра действия формы. По умолчанию данные формы отправляются методом http POST.
action = 'URL'
В следующем коде форма с именем AdmissionForm разработана с использованием описанных выше виджетов. Добавьте этот код в root.py перед классом RootController.
class AdmissionForm(twf.Form):
class child(twf.TableLayout):
NameOfStudent = twf.TextField(size = 20)
AddressForCorrespondance = twf.TextArea("", rows = 5, cols = 30)
PINCODE = twf.NumberField(value = 431602)
DateOfBirth = twd.CalendarDatePicker()
EmailID = twf.EmailField()
Gender = twf.RadioButtonList(options = ["Male","Female"],value = 'Male')
Subjects = twf.CheckBoxList(options = ['TurboGears', 'Flask', 'Django', 'Pyramid'])
MediumOfInstruction = twf.SingleSelectField(prompt_text = 'choose',
options = ['English', 'Hindi', 'Marathi', 'Telugu'])
action = '/save_form'
submit = twf.SubmitButton(value ='Submit')
Теперь сохраните этот код ниже как twform.html в каталоге шаблонов -
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>TurboGears Form Example</title>
</head>
<body>
<div id = "tw form">
${form.display(value = dict(title = 'default title'))}
</div>
</body>
</html>
В классе RootController (в root.py) добавьте следующую функцию контроллера -
@expose('hello.templates.twform')
def twform(self, *args, **kw):
return dict(page = 'twform', form = MovieForm)
В классе AdmissionForm у нас есть stipulated/save_formкак URL-адрес действия. Следовательно, добавьтеsave_form() функция в RootController.
@expose()
def save_movie(self, **kw):
return str(kw)
Убедитесь, что сервер работает (с помощью коробки передач). Войтиhttp://localhost:8080/twform в браузере.
Нажатие кнопки отправки отправит эти данные в save_form() URL-адрес, который отобразит данные формы в виде объекта словаря.
{
'EmailID': u'[email protected]',
'NameOfStudent': u'Malhar Lathkar',
'Gender': u'Male',
'PINCODE': u'431602',
'DateOfBirth': u'2015-12-29',
'Subjects': [u'TurboGears', u'Flask', u'Django'],
'MediumOfInstruction': u'',
'AddressForCorrespondance': u'Shivaji Nagar\r\nNanded\r\nMaharashtra'
}
В хорошей библиотеке виджетов Forms должна быть функция проверки ввода. Например, пользователя следует заставить ввести данные в обязательное поле или проверить, содержит ли поле электронной почты действительный адрес электронной почты, не прибегая к каким-либо другим программным средствам (например, функциям JavaScript) для проверки.
Ранние версии библиотеки форм ToscaWidgets, которые полагались на модуль FormEncode для поддержки проверки. ToscaWidgets2 теперь имеет встроенную поддержку проверки, доступную в модуле tw2.core. Однако по-прежнему можно использовать методы проверки FormEncode.
Для проверки формы ToscaWidgets используется декоратор @validate.
@validate(form, error_handler, validators)
В ’form’ - проверяемый объект формы ToscaWidgets.
В ‘error-handler’ это метод контроллера, используемый для обработки ошибок формы.
В ‘validators’ являются объектом словаря, содержащим валидаторы FormEncode.
Типы валидаторов
Модуль tw2.core содержит класс валидатора, от которого унаследованы другие валидаторы. Также на его основе можно разработать собственный валидатор. Некоторые из важных валидаторов описаны ниже -
LengthValidator- Проверьте, имеет ли значение заданную длину. Минимальные и максимальные пределы определяются с помощью параметров min и max. Пользовательские сообщения для длины ниже и выше min и max можно указать как параметр tooshort и toolong.
tw2.core.LengthValidator(min = minval, max = maxval,
msgs = { 'tooshort': (‘message for short length’),
'toolong': (‘message for long length)})
RangeValidator- Обычно используется вместе с RangeField. Полезно проверять значение числового поля в минимальных и максимальных пределах. Сообщения для параметров tooshort и toolong можно настроить.
tw2.core.RangeValidator(min = minval, max = maxval,
msgs = { 'tooshort': (‘message for short length’),
'toolong': (‘message for long length)})
IntValidator- Этот класс является производным от RangeValidator. Обычно это используется для проверки того, содержит ли ввод в обычном текстовом поле целочисленные данные. Можно установить минимальные и максимальные пределы, а также сообщения об ошибках. Кроме того, сообщение об ошибке для нецелочисленного ввода можно указать как параметр notint.
tw2.core.IntValidator(msgs = {‘notint’:’Must be Integer’})
OneOfValidator - Этот валидатор заставляет пользователя выбирать значение только из доступных вариантов в списке.
tw2.core.OneOfValidator(values = [option1, option2,..],
msgs = {‘notinlist’:’Not in List’}}
DateValidator- Очень полезно для проверки правильности даты, введенной пользователем. Формат даты (по умолчанию YMD) и сообщение об ошибке можно настроить. Также можно указать минимальные и максимальные пределы дат. DateTimeValidator также доступен для проверки объекта класса DateTime.
tw2.core.DateValidator(msgs = {format = ’%Y-%m-%d’,
'baddatetime': ('baddate', ('Must follow date format $format_str'))}
EmailValidator- Проверяет ввод пользователя на действительный адрес электронной почты. Этот класс унаследован от более общего RegexValidator.
tw2.core.EmailValidator(msgs = {'badregex': ('bademail',
('Must be a valid email address')) }
UrlValidator- Этот класс также унаследован от RegexValidator. Он проверяет ввод пользователя на действительный URL-адрес.
tw2.core.UrlValidator(msgs = {'badregex': ('badurl', ('Must be a valid URL’)) }
MatchValidator- Подтверждает, совпадает ли значение одного поля с другим. Это особенно полезно, когда от пользователя требуется выбрать и подтвердить поле пароля. Типичное использование MatchValidator показано ниже -
import tw2.core as twc
import tw2.forms as twf
class AdmissionForm(twf.Form):
class child(twf.TableLayout):
validator = twc.MatchValidator('pw', 'pwconfirm')
pw = twf.PasswordField()
pwconfirm = twf.PasswordField()
Также возможно создать составной валидатор, где желательно, чтобы валидация прошла успешно, если какая-либо из проверок пройдена. В других случаях вы можете захотеть, чтобы проверка прошла успешно, только если входные данные проходят все проверки. Для этого tw2.core предоставляет валидаторы Any и All, которые являются подклассами расширяемого CompoundValidator.
TurboGears предоставляет очень удобную систему обмена сообщениями для ненавязчивого уведомления пользователя. Класс TGFlash в модуле tg обеспечивает поддержку мигающих сообщений, которые хранятся в обычном файле cookie. Этот класс поддерживает получение флэш-сообщений на стороне сервера, а также на стороне клиента через JavaScript.
В render()Метод класса TGFlash при использовании из самого Python может быть вызван из шаблона для отображения флэш-сообщения. Если используется в JavaScript, он предоставляет объект WebFlash. Он обнажаетpayload() и render() методы для получения текущего флэш-сообщения и его рендеринга из JavaScript.
Когда проект TurboGears создается с использованием «быстрого старта», он имеет шаблон Master.html. Он содержит определение переменной этого flash-объекта. Содержимое этого флэш-сообщения, полученного от контроллера, заменяет отмеченный заполнитель в этом шаблоне.
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
В tg.flash_obj - это объект WebFlash, который доступен внутри любого отображаемого шаблона путем включения master.htmlшаблон. Этот объект позволяет получить текущее флэш-сообщение и отобразить его.
Сообщения Flash хранятся в файле cookie (имя которого по умолчанию - webflash) с помощью tg.flash()метод. Затем ему передаются параметры сообщения и состояния.
tg.flash('Message', 'status')
Если метод, который называется flash, выполняет перенаправление, то флэш-память будет видна внутри перенаправленной страницы. Если метод напрямую предоставляет шаблон, то флэш-память будет видна внутри самого шаблона.
Внешний вид флэш-сообщения можно настроить, применив стили CSS к коду состояния. «Быстрый запуск» проекта содержит коды состояния ошибок, предупреждений, информации и ОК, настроенные с помощью таблицы стилей public / css / style.css. Также можно добавить больше кодов состояния со стилями.
#flash > .warning {
color: #c09853;
background-color: #fcf8e3;
border-color: #fbeed5;
}
#flash > .ok {
color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
}
#flash > .error {
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}
#flash > .info {
color: #3a87ad;
background-color: #d9edf7;
border-color: #bce8f1;
}
Эта внешняя таблица стилей должна быть включена в шаблон -
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
Конфигурация поддержки любых сообщений Flash может быть достигнута путем установки параметров для метода configure () объекта TGFlash или в app_cfg.py (в папке config). Настраиваемые параметры:
Sr.No. | Параметры и описание |
---|---|
1 | flash.cookie_name Имя файла cookie, используемого для хранения мгновенных сообщений. По умолчаниюwebflash. |
2 | flash.default_status Статус сообщения по умолчанию, если не указан (по умолчанию нормально) |
3 | flash.template Используется как flash template при рендеринге. |
4 | flash.allow_html Повороты on/off escaping in flash messages, по умолчанию HTML не разрешен. |
5 | flash.js_call Код JavaScript, который будет запускаться при отображении flash из JavaScript. По умолчаниюwebflash.render() |
6 | flash.js_template string.Template Экземпляр используется для замены полной поддержки JavaScript для флеш-сообщений. |
pop_payload() - функция fetches current flash message, statusи сопутствующая информация. При получении флэш-сообщения файл cookie будет удален.
render(container_id, use_js=True) - Визуализируйте флэш-сообщение внутри шаблона или предоставьте для них поддержку Javascript.
container_id - это DIV, в котором будут отображаться сообщения, в то время как use_js переключает между рендерингом flash в формате HTML или для использования JavaScript.
status - Получить только текущий статус флеш-памяти, получение статуса флеш-памяти удалит cookie.
message - Получить только текущее флэш-сообщение, получение флэш-сообщения удалит cookie.
Как сделать простое флеш-сообщение?
В следующем примере метод flash () предоставляется в классе корневого контроллера. Он вызывает сообщение flash (), которое отображается в открытом шаблоне flash.html.
from hello.lib.base import BaseController
from tg import expose, flash, redirect, request
class RootController(BaseController):
@expose('hello.templates.flash')
def flash(self, user = None):
if user:
flash(message = "Welcome "+user,status = "ok")
else:
flash(message = "Welcome Guest",status = "info")
return {}
Код для создания flash.html в папке шаблонов выглядит следующим образом
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears 2.3: Flash messages>/title>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
</head>
<body>
<h2>Hello TurboGears</h2>
</body>
</html>
Запустите сервер и введите http://localhost:8080/flash?user=MVL в браузере
Измените URL на http://localhost:8080/flash и увидеть флэш-сообщение, отформатированное по-разному согласно определению в style.css
Часто требуется хранить простые данные о просмотре, прикрепленные к браузеру пользователя. Сеансы - наиболее часто используемый метод. Сеанс представляет данные, которые не нужно хранить в более постоянной форме, такой как файл на диске или база данных.
Однако данные сеанса в TurboGears могут поддерживаться файловой системой, базой данных или значениями хешированных файлов cookie. Небольшой объем данных сеанса обычно хранится в файлах cookie, но для большего объема данных сеанса используется MemCache.
MemCache - это демон системного уровня. Он обеспечивает быстрый доступ к кэшированным данным и чрезвычайно масштабируем. Однако он предназначен для использования только на защищенных серверах и, следовательно, должен поддерживаться и защищаться системным администратором.
Стакан в управлении сеансом
TurboGears использует Beaker для управления сеансом. Проект, запускаемый с помощью gearbox, по умолчанию настроен на использование хешированных файлов cookie для хранения данных сеанса.
Каждый раз, когда клиент подключается, промежуточное программное обеспечение сеанса (Beaker) проверяет файл cookie, используя имя файла cookie, которое было определено в файле конфигурации. Если cookie не найден, он будет установлен в браузере. При всех последующих посещениях промежуточное ПО находит файл cookie и использует его.
Чтобы включить управление сеансом, класс сеанса должен быть включен в проект следующим оператором импорта -
from tg import session
Чтобы сохранить данные в переменной сеанса -
session[‘key’] = value
session.save()
Чтобы получить переменную сеанса -
return session[‘key’]
Обратите внимание, что вам необходимо явно сохранить сеанс, чтобы ваши ключи были сохранены в этом сеансе.
В delete() метод объекта сеанса сотрет все пользовательские сеансы -
session.delete()
Несмотря на то, что не принято удалять все пользовательские сеансы в любой данной производственной среде, вы обычно делаете это для очистки после того, как были выполнены тесты удобства использования или функциональные тесты.
Ниже приведен простой пример для демонстрации сеансов. Класс RootController имеетsetsession() метод, который устанавливает переменную сеанса.
from hello.lib.base import BaseController
from tg import expose, session
class RootController(BaseController):
@expose()
def setsession(self):
session['user'] = 'MVL'
session.save()
str = "<b>sessionVariable set to "+session['user']
str = str+"<br><a href = '/getsession'>click here to retrieve</a></b>"
return str
@expose()
def getsession(self):
return "<b>value of session variable retrieved " +session['user'] +"</b>"
Войти http://localhost:8080/setsession
Ссылка в браузере ведет на http://localhost:8080/getsession который извлекает и отображает переменную сеанса -
Чтобы повысить производительность веб-приложения, особенно если оно связано с длительными операциями, используются методы кэширования. TurboGears предоставляет два типа методов кэширования:
Whole-page Caching
Он работает на уровне протокола HTTP, чтобы избежать полных запросов к серверу, если браузер пользователя или промежуточный прокси-сервер (например, Squid) перехватит запрос и вернет кэшированную копию файла.
Application-level Caching
Это работает на сервере приложений для кэширования вычисленных значений, часто результатов сложных запросов к базе данных, так что будущие запросы могут избежать необходимости повторного вычисления значений. Для веб-приложений кэширование на уровне приложения обеспечивает гибкий способ кэширования результатов сложных запросов, так что общая нагрузка на данный метод контроллера может быть уменьшена до нескольких запросов для конкретного пользователя или конкретного случая и накладных расходов на рендеринг шаблона. .
Кэширование на уровне приложений
Как упоминалось ранее, проект TurboGears с быстрым запуском настроен для включения поддержки кэширования пакета Beaker. Beaker поддерживает следующие серверы, используемые для хранения кеша:
memory- Используется для хранения по процессам. Это очень быстро.
filesystem - хранилище для каждого процесса, а также для нескольких процессов.
DBM database - на процесс, на несколько процессов, довольно быстро.
SQLAlchemy database- хранилище на сервере базы данных. Медленнее по сравнению с приведенными выше вариантами.
Memcached - кеш-память на базе многосерверной памяти.
Кэширование контроллера
Для быстрого кэширования контроллера cached()декоратор доступен. Все тело контроллера кэшируется в зависимости от различных параметров запроса. Определениеtg.decorators.cached() декоратор выглядит следующим образом
tg.decorators.cached(key, expire, type,
query-args, cache_headers, invalidate_on_startup, cache_response)
Описание параметров следующее -
Sr.No. | Параметры и описание |
---|---|
1 | key Задает параметры контроллера, используемые для генерации ключа кеша. |
2 | expire Время в секундах до истечения срока действия кеша, по умолчанию - «никогда». |
3 | Type dbm, memory, file, memcached или None. |
4 | cache_headers Кортеж имен заголовков, указывающий заголовки ответа. |
5 | invalidate_on_startup Если True, кеш становится недействительным при каждом запуске или перезапуске приложения. |
6 | cache_response ответ должен быть кэширован или нет, по умолчанию - True. |
Ниже приведен пример кеширования контроллера -
@cached(expire = 100, type = 'memory')
@expose()
def simple(self):
return "This is a cached controller!"
Кэширование на уровне шаблона
Механизм шаблонов Genshi извлекает шаблон из кеша, если его содержимое не изменилось. По умолчанию размер этого кэша равен 25. По умолчанию автоматическая перезагрузка шаблонов истинна. Для повышения производительности вapp_cfg.py -
[app:main]
genshi.max_cache_size = 100
auto_reload_templates = false
Чтобы кэшировать шаблон, вам просто нужно вернуть tg_cache параметр от контроллера, который отображает кэшированный шаблон.
Tg_cache - это словарь, который принимает следующие ключи:
key - Ключ кеша. Default: Никто.
expire - как долго кеш должен оставаться в живых. Default: никогда не заканчивается
type - память, dbm, memcached. Default: dbm.
В следующем примере показано кеширование шаблона -
@expose(hello.templates.user')
def user(self, username):
return dict(user = username, tg_cache = dict(key = user, expire = 900))
Хотя можно использовать SQL в приложении TurboGears для выполнения операций CRUD с любой реляционной базой данных, рекомендуется использовать SQLAlchemy, набор инструментов Python - это мощный объектно-реляционный сопоставитель, который дает разработчикам приложений полную мощность и гибкость SQL. Помимо поддержки баз данных на основе SQL через SQLAlchemy, TurboGears также поддерживает базу данных MongoDB через Ming. В этом разделе обсуждается функциональность SQLAlchemy.
Что такое ORM (объектно-реляционное сопоставление)?
Большинство платформ языков программирования являются объектно-ориентированными. С другой стороны, данные на серверах СУБД хранятся в виде таблиц. Сопоставление объектных отношений - это метод сопоставления параметров объекта с базовой структурой таблицы СУБД. ORM API предоставляет методы для выполнения операций CRUD без необходимости писать необработанные операторы SQL.
Когда проект TurboGears создается с помощью команды 'quickstart' из набора инструментов gearbox, поддержка SQLAlchemy включается по умолчанию следующими параметрами конфигурации:
config['use_sqlalchemy'] = True
config['sqlalchemy.url'] = 'sqlite:///devdata.db'
«Быстрый запуск» проекта также создает в нем пакет моделей. Например, проект Hello будет иметь Hello \ hello \ model. В этом пакете созданы следующие файлы -
__init__.py- Здесь настраивается доступ к базе данных. В этот модуль импортируются объекты модели приложения. Он также имеет DBSession - глобальный менеджер сеансов, а также DeclarativeBase, который является базовым классом для всех классов модели.
auth.py- Здесь определяются модели, используемые стеком аутентификации. Дополнительные модели баз данных хранятся в этом пакете как отдельный модуль и добавляются в __init__.py.
Давайте добавим модель ученика, которая создаст стол ученика в нашем sqlite база данных.
Hello\hello\model\student.py
from sqlalchemy import *
from sqlalchemy.orm import mapper, relation, relation, backref
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Integer, Unicode, DateTime
from hello.model import DeclarativeBase, metadata, DBSession
from datetime import datetime
class student(DeclarativeBase):
__tablename__ = 'student'
uid = Column(Integer, primary_key = True)
name = Column(Unicode(20), nullable = False, default = '')
city = Column(Unicode(20), nullable = False, default = '')
address = Column(Unicode(100), nullable = False, default = '')
pincode = Column(Unicode(10), nullable = False, default = '')
Теперь добавьте эту модель в init_model() функция внутри __init__.py.Эта функция уже содержит в себе модель аутентификации. Добавьте модель нашего студента под ним.
# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student
Если вы хотите, чтобы таблица была инициализирована некоторыми данными во время настройки моделей, добавьте ее в bootstrap.py в пакете websetup. Добавьте следующие утверждения вbootstrap() функция.
s1 = model.student()
s1.name = 'M.V.Lathkar'
s1.city = 'Nanded'
s1.address = 'Shivaji Nagar'
s1.pincode = '431602'
model.DBSession.add(s1)
model.DBSession.flush()
transaction.commit()
Модели инициализируются запуском команды setup-app коробки передач -
gearbox setup-app
Объект сеанса SQLAlchemy управляет всеми операциями сохранения объекта ORM.
Следующие методы сеанса выполняют операции CRUD -
DBSession.add(model object) - вставляет запись в отображаемую таблицу.
DBSession.delete(model object) - удаляет запись из таблицы.
DBSession.query(model).all() - извлекает все записи из таблицы (соответствует запросу SELECT).
Вы можете применить фильтр к полученному набору записей с помощью атрибута filter. Например, чтобы получить записи с city = 'Hyderabad' в таблице студентов, используйте следующий оператор -
DBSession.query(model.student).filter_by(city = ’Hyderabad’).all()
Теперь мы увидим, как взаимодействовать с моделями через URL-адреса контроллеров.
Сначала давайте разработаем форму ToscaWidgets для ввода данных студента.
Hello\hello\controllers.studentform.py
import tw2.core as twc
import tw2.forms as twf
class StudentForm(twf.Form):
class child(twf.TableLayout):
name = twf.TextField(size = 20)
city = twf.TextField()
address = twf.TextArea("",rows = 5, cols = 30)
pincode = twf.NumberField()
action = '/save_record'
submit = twf.SubmitButton(value = 'Submit')
В RootController (root.py приложения Hello) добавьте следующий URL-адрес сопоставления функции '/ add' -
from hello.controllers.studentform import StudentForm
class RootController(BaseController):
@expose('hello.templates.studentform')
def add(self, *args, **kw):
return dict(page='studentform', form = StudentForm)
Сохраните следующий HTML-код как studentform.html в папке шаблонов -
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>Student Registration Form</title>
</head>
<body>
<div id = "getting_started">
${form.display(value = dict(title = 'Enter data'))}
</div>
</body>
</html>
Войти http://localhost:8080/addв браузере после запуска сервера. В браузере откроется следующая форма информации о студенте -
Вышеуказанная форма предназначена для отправки в ‘/save_record’URL. Следовательноsave_record() функцию необходимо добавить в root.pyвыставить его. Данные из формы ученика принимаются этой функцией какdict()объект. Он используется для добавления новой записи в таблицу учеников, лежащую в основе модели ученика.
@expose()
#@validate(form = AdmissionForm, error_handler = index1)
def save_record(self, **kw):
newstudent = student(name = kw['name'],city = kw['city'],
address = kw['address'], pincode = kw['pincode'])
DBSession.add(newstudent)
flash(message = "new entry added successfully")
redirect("/listrec")
Обратите внимание, что после успешного добавления браузер будет перенаправлен на ‘/listrec’ URL. Этот URL предоставляетсяlistrec() function. Эта функция выбирает все записи в таблице студентов и отправляет их в форме объекта dict в шаблон studentlist.html. Этотlistrec() функция выглядит следующим образом -
@expose ("hello.templates.studentlist")
def listrec(self):
entries = DBSession.query(student).all()
return dict(entries = entries)
Шаблон studentlist.html выполняет итерацию по объекту словаря записей с помощью директивы py: for. Шаблон studentlist.html выглядит следующим образом:
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/">
<head>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
<title>Welcome to TurboGears</title>
</head>
<body>
<h1>Welcome to TurboGears</h1>
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
<h2>Current Entries</h2>
<table border = '1'>
<thead>
<tr>
<th>Name</th>
<th>City</th>
<th>Address</th>
<th>Pincode</th>
</tr>
</thead>
<tbody>
<py:for each = "entry in entries">
<tr>
<td>${entry.name}</td> <td>${entry.city}</td>
<td>${entry.address}</td> <td>${entry.pincode}</td>
</tr>
</py:for>
</tbody>
</table>
</body>
</html>
Теперь вернемся к http://localhost:8080/addи введите данные в форму. При нажатии на кнопку отправки в браузере откроется страница studentlist.html. Также появится сообщение «новая запись успешно добавлена».
ToscaWidgets содержит элемент управления DataGrid, который обеспечивает быстрый способ представления данных в табличной форме. Объект DataGrid объявлен следующим образом -
from tw2.forms import DataGrid
student_grid = DataGrid(fields = [('Name', 'name'),('City', 'city'),
('Address','address'), ('PINCODE', 'pincode')])
Теперь функция showgrid () извлекает все записи из таблицы учеников и предоставляет данные в шаблон grid.html. Сначала код функции showgrid (), а затем код grid.html приведен ниже -
showgrid ()
@expose('hello.templates.grid')
def showgrid(self):
data = DBSession.query(student).all()
return dict(page = 'grid', grid = student_grid, data = data)
grid.html
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>Student Registration Form</title>
</head>
<body>
<div id = "getting_started">
<div>${grid.display(value = data)}</div>
</div>
</body>
</html>
Следующие табличные данные будут отображаться, когда http://localhost:8080/showlist URL вводится в браузере -
TurboGears предоставляет удобный декоратор paginate () для разделения вывода по страницам. Этот декоратор сочетается с декоратором expose (). Декоратор @Paginate () принимает в качестве аргумента объект словаря результата запроса. Кроме того, количество записей на странице определяется значением атрибута items_per_page. Убедитесь, что вы импортируете функцию paginate из tg.decorators в свой код.
Перепишите функцию listrec () в root.py следующим образом:
from tg.decorators import paginate
class RootController(BaseController):
@expose ("hello.templates.studentlist")
@paginate("entries", items_per_page = 3)
def listrec(self):
entries = DBSession.query(student).all()
return dict(entries = entries)
Элементов на странице установлено три.
В шаблоне studentlist.html навигация по страницам включается путем добавления tmpl_context.paginators.entries.pager () под директивой py: for. Код для этого шаблона должен быть таким, как показано ниже -
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/">
<head>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
<title>Welcome to TurboGears</title>
</head>
<body>
<h1>Welcome to TurboGears</h1>
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
<h2>Current Entries</h2>
<table border = '1'>
<thead>
<tr>
<th>Name</th>
<th>City</th>
<th>Address</th>
<th>Pincode</th>
</tr>
</thead>
<tbody>
<py:for each = "entry in entries">
<tr>
<td>${entry.name}</td> <td>${entry.city}</td>
<td>${entry.address}</td> <td>${entry.pincode}</td>
</tr>
</py:for>
<div>${tmpl_context.paginators.entries.pager()}</div>
</tbody>
</table>
</body>
</html>
Войти http://localhost:8080/listrecв браузере. Отображается первая страница записей в таблице. Вверху этой таблицы также видны ссылки на номера страниц.
Как добавить поддержку пагинации в Datagrid
Также возможно добавить поддержку нумерации страниц в сетку данных. В следующем примере сетка данных с разбивкой на страницы предназначена для отображения кнопки действия. Чтобы активировать кнопку действия, объект datagrid создается со следующим кодом -
student_grid = DataGrid(fields = [('Name', 'name'),('City', 'city'),
('Address','address'), ('PINCODE', 'pincode'),
('Action', lambda obj:genshi.Markup('<a
href = "%s">Edit</a>' % url('/edit',
params = dict(name = obj.name)))) ])
Здесь кнопка действия связана с параметром имени каждой строки в сетке данных.
Перепишите showgrid() функционируют следующим образом -
@expose('hello.templates.grid')
@paginate("data", items_per_page = 3)
def showgrid(self):
data = DBSession.query(student).all()
return dict(page = 'grid', grid = student_grid, data = data)
Браузер показывает разбитую на страницы сетку данных следующим образом:
При нажатии кнопки «Изменить» в третьей строке выполняется перенаправление на следующий URL-адрес. http://localhost:8080/edit?name=Rajesh+Patil
TurboGears предоставляет расширение tgext.admin, которое поддерживается tgext.crud и sprox. Этот Sprox - это пакет, используемый для создания веб-виджетов непосредственно из схемы базы данных. Это можно использовать для автоматического создания простых страниц администрирования и является набором инструментов для страницы / admin в недавно запущенных приложениях.
По умолчанию администратор предоставит автоматически сгенерированный доступ ко всем моделям, импортированным в ваш проект models / __ init__.py.
Как создать администратора TurboGears
Администратор TurboGears по умолчанию создается как объект класса AdminController -
from tgext.admin.controller import AdminController
class RootController(BaseController):
admin = AdminController(model, DBSession, config_type = TGAdminConfig)
Это создает администратора для всех моделей с конфигурацией администратора TurboGears по умолчанию.
Через менеджер был создан пользователь на этапе настройки. Теперь можно получить доступ к администратору TurboGears по адресуhttp://localhost:8080/adminПри первом доступе к этой странице она запросит аутентификацию. Вы можете просто указать имя пользователя и пароль пользователя, созданного для нас командой setup-app -
Username: manager
Password: managepass
Чтобы войти в проект быстрого запуска, добавьте следующие функции в класс RootController (controllers / root.py).
from hello.lib.base import BaseController
from tg import expose, flash, redirect, request,url, lurl
from tg import redirect, validate
from hello import model
from hello.model import DBSession
from tgext.admin.tgadminconfig import BootstrapTGAdminConfig as TGAdminConfig
from tgext.admin.controller import AdminController
from tg.exceptions import HTTPFound
class RootController(BaseController):
admin = AdminController(model, DBSession, config_type = TGAdminConfig)
@expose('hello.templates.index')
def index(self):
return dict(page = 'index')
@expose('hello.templates.login')
def login(self, came_from = lurl('/'), failure = None, login = ''):
if failure is not None:
if failure == 'user-not-found':
flash(_('User not found'), 'error')
elif failure == 'invalid-password':
flash(_('Invalid Password'), 'error')
login_counter = request.environ.get('repoze.who.logins', 0)
if failure is None and login_counter > 0:
flash(_('Wrong credentials'), 'warning')
return dict(page = 'login', login_counter = str(login_counter),
came_from = came_from, login = login)
@expose()
def post_login(self, came_from = lurl('/')):
if not request.identity:
login_counter = request.environ.get('repoze.who.logins', 0) + 1
redirect('/login', params = dict(came_from = came_from,
__logins = login_counter))
userid = request.identity['repoze.who.userid']
flash(('Welcome back, %s!') % userid)
return HTTPFound(location = came_from)
Войдите в приложение для быстрого запуска после запуска сервера и посетив http://localhost:8080/loginа затем введите учетные данные менеджера, как показано выше. Браузер отобразит страницу администратора, подобную показанной ниже -
На странице показаны все модели, созданные в этом приложении. Вы можете щелкнуть любую модель, чтобы увидеть список записей в ней -
Кнопка «Новый» в верхней части этой сетки данных позволяет добавить запись. Точно так же кнопки действий для редактирования и удаления записи также представлены в столбце действий этой таблицы данных. Также отображается поле поиска для условного выбора записей.
Приложение TurboGears создается с помощью параметров быстрого запуска и настройки приложения набора инструментов коробки передач, в котором по умолчанию включена поддержка авторизации и аутентификации. Модели, объявленные в auth.py, настраиваются и инициализируются в соответствии со значениями, назначенными в bootstrap.py.
Следующие модели объявлены в auth.py -
Модель пользователя
Модель User содержит дизайн таблицы tg_user. Эта таблица используется пакетом repose.who. Этот пакет repose.who является мощной, а также расширяемой библиотекой аутентификации для приложений WSGI. Структура модели пользователя следующая -
class User(DeclarativeBase):
"""
__tablename__ = 'tg_user'
user_id = Column(Integer, autoincrement = True, primary_key=True)
user_name = Column(Unicode(16), unique = True, nullable = False)
email_address = Column(Unicode(255), unique = True,nullable=False)
display_name = Column(Unicode(255))
_password = Column('password', Unicode(128))
created = Column(DateTime, default = datetime.now)
Эта групповая модель содержит определение таблицы tg_group. Его определение дается в auth.py следующим образом:
class Group(DeclarativeBase):
__tablename__ = 'tg_group'
group_id = Column(Integer, autoincrement = True,primary_key = True)
group_name = Column(Unicode(16),unique = True,nullable = False)
display_name = Column(Unicode(255))
created = Column(DateTime, default = datetime.now)
Также настраивается другое разрешение модели, которое содержит определение разрешения.
class Permission(DeclarativeBase):
__tablename__ = 'tg_permission'
permission_id = Column(Integer,autoincrement = True,primary_key = True)
permission_name = Column(Unicode(63), unique = True, nullable = False)
description = Column(Unicode(255))
Во время настройки моделей в эти таблицы добавляются следующие данные:
u = model.User()
u.user_name = 'manager'
u.display_name = 'Example manager'
u.email_address = '[email protected]'
u.password = 'managepass'
model.DBSession.add(u)
g = model.Group()
g.group_name = 'managers'
g.display_name = 'Managers Group'
g.users.append(u)
model.DBSession.add(g)
p = model.Permission()
p.permission_name = 'manage'
p.description = 'This permission gives an administrative right'
p.groups.append(g)
model.DBSession.add(p)
u1 = model.User()
u1.user_name = 'editor'
u1.display_name = 'Example editor'
u1.email_address = '[email protected]'
u1.password = 'editpass'
model.DBSession.add(u1)
Модель предиката
Модуль предикатов в пакете tg содержит определения для средств проверки предикатов. Предикат - это условие, которое должно быть выполнено, чтобы пользователь мог получить доступ к запрошенному источнику. Такой предикат или условие может состоять из нескольких предикатов - они называются составными предикатами. Контроллеры действий или контроллеры могут иметь только один предикат, будь то одиночный или составной.
Если пользователь не вошел в систему или не имеет необходимых разрешений, эта программа проверки предикатов выдает ошибку 401 (HTTP Unauthorized), которая перехватывается промежуточным программным обеспечением repoze.who для отображения страницы входа, позволяющей пользователю войти в систему, и перенаправления пользователь вернется на нужную страницу, когда они будут закончены.
Различные условия или предикаты, определенные в модуле tg.predicates:
Sr.No. | Модуль tg.predicates и описание |
---|---|
1 | All Проверить, соблюдены ли все указанные предикаты |
2 | Any Проверить, выполняется ли хотя бы один из указанных предикатов |
3 | is_user Убедитесь, что имя пользователя аутентифицированного пользователя является указанным |
4 | in_group Убедитесь, что пользователь принадлежит к определенной группе. |
5 | in_all_groups Убедитесь, что пользователь принадлежит ко всем указанным группам. |
6 | in_any_group Убедитесь, что пользователь принадлежит хотя бы к одной из указанных групп. |
7 | is_anonymous Убедитесь, что текущий пользователь анонимен. |
8 | has_permission Убедитесь, что текущий пользователь имеет указанное разрешение. |
9 | has_all_permissions Убедитесь, что текущему пользователю предоставлены все указанные разрешения. |
10 | has_any_permission Убедитесь, что у пользователя есть хотя бы одно из указанных разрешений. |
Например, если у вас есть предикат, grant access user belonging to customers group, то вы можете использовать следующую встроенную проверку предикатов -
from tg.predicates import in_group
p in_group(‘customers’)
Следующая проверка предикатов предоставит доступ пользователю root или любому лицу с разрешением на управление:
from tg.predicates import Any, is_user, has_permission
p = Any(is_user('root'), has_permission('manage'),
sg = 'Only administrators can remove blog posts')
TurboGears также поддерживает базы данных документов MongoDB. Он использует Ming, API-интерфейс Object Document Mapper. Использование Ming очень похоже на SQLAlchemy. Язык запросов Ming позволяет переносить проект TurboGears на основе SQLAlchemy в Ming.
Что такое PyMongo
PyMongo - это дистрибутив Python, содержащий инструменты для работы с MongoDB. Ming расширяет PyMongo, обеспечивая -
- Декларативные модели
- Проверка и преобразование схемы
- Схема эволюции
- Чистая реализация MongoDB InMemory
- Единица работы
- Карта идентичности
- Отношения один-ко-многим, многие-к-одному и многие-ко-многим
Прежде всего, вам необходимо скачать и установить MongoDB. Последний дистрибутив MongoDB можно скачать сhttps://www.mongodb.org/downloads
В Windows запустите сервер MongoDB, указав параметр -dbpath -
C:\mongodb\bin>Mongod --dbpath d:\mongo
D:\mongo folderпредназначен для хранения базы данных MongoDB. Сервер начинает прослушивание вhttp://localhost:27017. Теперь, чтобы запустить оболочку MongoDB, используйте следующую команду -
C:\mongodb\bin>Mongo
Наша среда MongoDB готова.
Теперь создайте проект TurboGears с параметром -ming -
gearbox quickstart --ming Hello
Этот быстро запускаемый проект обеспечит уровень аутентификации и авторизации, аналогичный тому, который предусмотрен для версии SQLAlchemy. Это приложение теперь попытается подключиться к серверу через порт 27017 на локальном компьютере. Файл development.ini в папке проекта содержит следующие настройки -
ming.url = mongodb://localhost:27017/
ming.db = hello
Настройте проект, используя следующую команду -
Python setup.py develop
Папка проекта содержит подпапку моделей, в которой есть следующие файлы:
__init__.py - Вот где databaseдоступ настроен. Ваши коллекции должны бытьimported into this module. Например, мы добавим в этот пакет студенческую коллекцию.
session.py - Этот файл определяет session of your database connection. Вам нужно будет импортировать это каждый раз, когда вам нужно будет объявитьMappedClass указать сеанс для perform queries.
auth.py - Этот файл будет создан, если у вас есть enabled authentication and authorizationв кратком руководстве. Он определяет три коллекцииrepoze.who, который в дальнейшем зависит от: пользователя, группы и разрешения.
Определение вашей коллекции
По умолчанию TurboGears настраивает Ming в декларативном режиме. Это похоже на декларативную поддержку SQLAlchemy и требует, чтобы каждая модель наследовала от класса MappedClass.
MappedClass требует, чтобы внутри был доступен подкласс __mongometa__, который дополнительно предоставляет подробные сведения об имени коллекции, в которой хранятся документы, и сеансе, используемом для хранения документов.
MappedClass также содержит определение полей в документе. В модуле odm Минга есть определения различных типов свойств поля -
- FieldProperty
- ForeignIdProperty
- RelationProperty
В ming.schema module определяет следующие типы данных -
- ming.schema.Anything
- ming.schema.Array
- ming.schema.Binary
- ming.schema.Bool
- ming.schema.Float
- ming.schema.Int
- ming.schema.ObjectId
- ming.schema.Scalar
- ming.schema.String
Чтобы добавить коллекцию студентов в эту модель, сохраните следующий код как student.py в папке hello / models.
Привет \ models \ student.py
from ming import schema
from ming.odm import MappedClass
from ming.odm import FieldProperty, ForeignIdProperty
from hello.model import DBSession
Class student(MappedClass):
class __mongometa__:
session = DBSession
name = 'student'
_id = FieldProperty(schema.ObjectId)
name = FieldProperty(schema.String(required = True))
city = FieldProperty(schema.String(if_missing = ''))
address = FieldProperty(schema.String(if_missing = ''))
pincode = FieldProperty(schema.String(if_missing = ''))
Наконец, включите эту модель в hello \ models \ __ init__.py
# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student
Чтобы настроить эти модели, выполните следующую команду коробки передач -
Gearbox setup-app
Запустите сервер с помощью следующей команды gearbox -
Gearbox serve –reload –debug
Откройте домашнюю страницу этого приложения (http://localhost:8080/)и войдите с учетными данными менеджера. Страница администратора этого приложения покажет список настроенных моделей. (войти как менеджер, пароль managepass)
Создание коллекций также можно проверить в веб-интерфейсе MongoDB, а также в оболочке MongoDB.
ODMSession используется для выполнения нескольких операций с базой данных с использованием следующих функций:
- model.query.find()
- model.query.find_and_modify()
- model.remove()
- model.update()
- model.flush()
Разработка формы ToscoWidget
Теперь мы создадим форму ToscoWidget для ввода данных студента и добавим их в таблицу, лежащую в основе модели студента.
Ниже приведен код для создания studentform.py -
Привет \ контроллеры \ studentform.py
import tw2.core as twc
import tw2.forms as twf
class StudentForm(twf.Form):
class child(twf.TableLayout):
name = twf.TextField(size = 20)
city = twf.TextField()
address = twf.TextArea("",rows = 5, cols = 30)
pincode = twf.NumberField()
action = '/save_record'
submit = twf.SubmitButton(value = 'Submit')
В URL-адресе '/ add' приложения Rootcontroller, который вызывает функцию add (), которая откроет указанную выше форму в браузере. Его кнопка отправки затем вызывает функцию save_record (). Он извлекает данные формы и сохраняет их в таблице студентов и перенаправляет приложение на URL-адрес / listrec, который предоставляет шаблон списка студентов.
Root.py для этого действия выглядит следующим образом:
Привет / контроллеры / root.py
from hello.lib.base import BaseController
from tg import expose, flash, redirect, request,url, lurl
from tg import redirect, validate
from hello import model
from hello.model import DBSession
from hello.model.student import student
from hello.controllers.studentform import StudentForm
class RootController(BaseController):
@expose()
def index(self):
return "<h1>Hello World</h1>"
@expose ("hello.templates.studentlist")
def listrec(self):
entries = student.query.find()
return dict(entries = entries)
@expose('hello.templates.studentform')
def add(self, *args, **kw):
return dict(page = 'studentform', form = StudentForm)
@expose()
def save_record(self, **kw):
newstudent = student(name = kw['name'],city = kw['city'],
address = kw['address'], pincode = kw['pincode'])
DBSession.flush()
flash(message = "new entry added successfully")
redirect("/listrec")
В папке шаблонов создаются следующие шаблоны -
Привет \ templates \ studentform.html
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/" lang = "en">
<head>
<title>Student Registration Form</title>
</head>
<body>
<div id = "getting_started">
${form.display(value = dict(title = 'Enter data'))}
</div>
</body>
</html>
Привет \ templates \ studentlist.html
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/">
<head>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = ${tg.url('/css/style.css')}" /> <title>Welcome to TurboGears</title> </head> <body> <h1>Welcome to TurboGears</h1> <py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)"> <div py:if = "flash" py:replace = "Markup(flash)" /> </py:with> <h2>Current Entries</h2> <table border = '1'> <thead> <tr> <th>Name</th> <th>City</th> <th>Address</th> <th>Pincode</th> </tr> </thead> <tbody> <py:for each = "entry in entries"> <tr> <td>${entry.name}</td>
<td>${entry.city}</td> <td>${entry.address}</td>
<td>${entry.pincode}</td>
</tr>
</py:for>
</tbody>
</table>
</body>
</html>
Перезагрузите сервер и введите http://localhost:8080/add в браузере -
Каждый раз, когда данные добавляются и нажимается кнопка отправки, будет отображаться список текущих записей.
Набор инструментов Gearbox содержит команду scaffold, которая очень полезна для быстрого создания новых компонентов приложения TurboGears. Приложение, созданное с помощью команды быстрого запуска коробки передач, имеет шаблон скелета в папке модели (model.py.template), папке шаблонов (template.html.template) и папке контроллеров (controller.py.template). Эти файлы .template используются в качестве основы для создания новых шаблонов для приложения.
Например, чтобы создать новую модель с именем mymodel, просто выполните следующую команду -
gearbox scaffold model mymodel
Эта команда сгенерирует модель / mymodel.py с определенным в ней классом newmodel.
# -*- coding: utf-8 -*-
"""Mymodel model module."""
from sqlalchemy import *
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Integer, Unicode, DateTime, LargeBinary
from sqlalchemy.orm import relationship, backref
from hello.model import DeclarativeBase, metadata, DBSession
class Mymodel(DeclarativeBase):
__tablename__ = 'mymodels'
uid = Column(Integer, primary_key = True)
data = Column(Unicode(255), nullable = False)
user_id = Column(Integer, ForeignKey('tg_user.user_id'), index = True)
user = relationship('User', uselist = False,
backref = backref('mymodels',cascade = 'all, delete-orphan'))
__all__ = ['Mymodel']
Теперь пользователи могут вносить изменения в структуру таблицы в соответствии с их требованиями, а затем импортировать ее внутрь. model/__init__.py чтобы сделать модель доступной внутри приложения.
Чтобы создать модель, класс контроллера для ее обработки и страницу индекса, все эти три компонента могут быть созданы одновременно с помощью следующей команды.
gearbox scaffold model controller template mymodel
Эта команда приведет к созданию controllers \ mymodel.py, в котором класс MymodelController определен должным образом.
# -*- coding: utf-8 -*-
"""Mymodel controller module"""
from tg import expose, redirect, validate, flash, url
# from tg.i18n import ugettext as _
# from tg import predicates
from hello.lib.base import BaseController
# from hello.model import DBSession
class MymodelController(BaseController):
# Uncomment this line if your controller requires an authenticated user
# allow_only = predicates.not_anonymous()
@expose('hello.templates.mymodel')
def index(self, **kw):
return dict(page = 'mymodel-index')
Чтобы начать использовать этот контроллер, смонтируйте его внутри вашего приложения RootController, чтобы определить экземпляр MymodelController. Добавьте эти строки в controllers \ root.py -
From hello.controller.mymodel import MymodelController
class RootController(BaseController): mymodel = MymodelController()
В папке шаблонов также будет создан шаблон scaffold templates \ mymodel.html. Он будет действовать как индексная страница для URL-адреса '/ mymodel'.
Созданный mymodel.html file в папке шаблонов будет следующее -
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<xi:include href = "master.html" />
<head>
<title>Mymodel</title>
</head>
<body>
<div class = "row">
<div class = "col-md-12">
<h2>Mymodel</h2>
<p>Template page for Mymodel</p>
</div>
</div>
</body>
</html>
В TurboGears есть три способа включить поведение в существующие приложения.
Hook - Это механизм, с помощью которого можно определить событие и уведомить зарегистрированных слушателей, как и когда события генерируются.
Controller Wrapper- Он находится между TurboGears и контроллером, поэтому контроллер можно расширить как декоратор. Таким образом, его можно прикрепить к любому стороннему приложению контроллера.
Application Wrapper - Он похож на любое промежуточное ПО WSGI, но работает только в контексте TurboGears.
В этой главе мы обсудим, как использовать хуки внутри существующего приложения.
Крючки
Хуки - это события, зарегистрированные в файле конфигурации приложения. app_cfg.py. Затем любой контроллер подключается к этим событиям декораторами событий.
Следующие крючки определены в TurboGears -
Sr.No. | Крючки и описание |
---|---|
1 | Startup() только для всего приложения, вызывается при запуске приложения. |
2 | shutdown() только для всего приложения, вызывается при выходе из приложения. |
3 | configure_new_app новое приложение создано конфигуратором приложений. |
4 | before_config(app) только для всего приложения, вызывается сразу после создания приложения, но перед настройкой параметров и промежуточного программного обеспечения |
5 | after_config(app) только для всего приложения, вызывается после завершения настройки. |
6 | before_validate Вызывается перед выполнением проверки |
7 | before_call Вызывается после проверки перед вызовом фактического метода контроллера. |
8 | before_render Вызывается перед отрисовкой шаблона контроллера, output - это возвращаемое контроллером значение. |
9 | after_render Вызывается после завершения рендеринга шаблона контроллера. |
Зарегистрировать крючок
Чтобы register a Hook, создавать функции в app_cfg.py а затем зарегистрируйте их, используя следующий код -
tg.hooks.register(hookane, function, controller)
В следующем коде хуки on_startup, on_shutdown и before_render зарегистрированы в app_cfg.py.
def on_startup():
print 'hello, startup world'
def on_shutdown():
print 'hello, shutdown world'
def before_render(remainder, params, output):
print 'system wide before render'
# ... (base_config init code)
tg.hooks.register('startup', on_startup)
tg.hooks.register('shutdown', on_shutdown)
tg.hooks.register('before_render', before_render)
Хук before_render регистрируется функцией контроллера в Rootcontroller. Добавьте следующий код в controllers \ root.py.
from tg.decorators import before_render
class RootController(BaseController):
@expose('hello.templates.index')
@before_render(before_render_cb)
def index(self, *args, **kw):
return dict(page = 'index')
Когда приложение обслуживается, в консоли отображается сообщение о запуске.
hello, startup world
Starting Standard HTTP server on http://127.0.0.1:8080
Когда в браузере вводится URL-адрес '/', на консоли отображается сообщение, соответствующее хуку before_render.
system wide before render
Going to render {'page': 'index'}
Расширения TurboGears обозначаются tgext.* package. Инструментарий Gearbox предоставляет команду tgext для создания образца расширения. Например -
gearbox tgext -n myextension
Другие необязательные параметры для этой команды:
--author - имя автора пакета.
--email - емейл автора пакета.
--licence- лицензия, используемая для пакета. По умолчанию - MIT.
--description - Описание упаковки.
--keywords - Ключевые слова пакета (по умолчанию: turbogears2.extension).
Это создаст каталог tgext.myextension, внутри которого есть простой пример расширения.
Run the setup.py внутри каталога -
Python setup.py install
В _init_.py файл внутри tgext/myextension папка содержит -
Plugme function - Это точка входа в расширение.
SetupExtension class - здесь происходит инициализация расширения.
On_startup function - внутри класса находится ловушка, зарегистрированная в функции __call__ внутри класса.
Краткая версия tgext\myextension\__init__.py.
from tg import config
from tg import hooks
from tg.configuration import milestones
import logging
log = logging.getLogger('tgext.myextension')
def plugme(configurator, options = None):
if options is None:
options = {}
log.info('Setting up tgext.myextension extension...')
milestones.config_ready.register(SetupExtension(configurator))
return dict(appid='tgext.myextension')
class SetupExtension(object):
def __init__(self, configurator):
self.configurator = configurator
def __call__(self):
log.info('>>> Public files path is %s' % config['paths']['static_files'])
hooks.register('startup', self.on_startup)
def echo_wrapper_factory(handler, config):
def echo_wrapper(controller, environ, context):
log.info('Serving: %s' % context.request.path)
return handler(controller, environ, context)
return echo_wrapper
self.configurator.register_wrapper(echo_wrapper_factory)
def on_startup(self):
log.info('+ Application Running!')
После установки расширения включите его, сделав следующие дополнения в приложении app_cfg.py конфигурационный файл.
from tgext.myextension import plugme
plugme(base_config)
Если мы запустим сервер с помощью команды сервера gearbox, уведомление о новом зарегистрированном расширении можно будет просмотреть на консоли следующим образом:
14:29:13,250 INFO [tgext.myextension] Setting up tgext.myextension extension...
14:29:13,453 INFO [tgext.myextension] >>> Public files path is c:\tghello\hello\hello\public
14:29:13,453 INFO [tgext.myextension] + Application Running!
Starting Standard HTTP server on http://127.0.0.1:8080
Если вашему расширению необходимо предоставлять модели и контроллеры, вы, вероятно, захотите взглянуть на Pluggable Applications, которые предназначены для создания многоразовых приложений Turbogears, которые можно подключать к другим приложениям для расширения их возможностей.
Используйте следующую команду коробки передач, чтобы создать подключаемое приложение -
gearbox quickstart-pluggable plugtest
Эти подключаемые приложения могут определять свои собственные -
Controllers - который будет автоматически смонтирован при очистке приложения.
Models - который будет доступен внутри и вне подключенного приложения.
Helpers - которые могут быть автоматически представлены в объекте «H» в шаблоне приложения.
Bootstrap - который будет выполнен при вызове setup-app.
Statics - которые будут доступны по их собственному частному пути.
Установите это приложение plugtest и смонтируйте его, внеся следующие изменения в app_cfg.py.
from tgext.pluggable import plug
plug(base_config, plugtest)
REST означает REпрезентационный Sтейт Tперевод. REST - это архитектура, основанная на веб-стандартах и использующая протокол HTTP для передачи данных. Он вращается вокруг ресурса, где каждый компонент является ресурсом, а доступ к ресурсу осуществляется через общий интерфейс с использованием стандартных методов HTTP. REST был впервые представленRoy Fielding in 2000.
Что такое RestController
RestController в TurboGears предоставляет механизм доступа к методу запроса, а не только к URL-адресу. Стандартный набор слов HTTP включает в себя: GET, POST, PUT и DELETE. RestController поддерживает их, а также добавляет несколько ярлыков для диспетчеризации URL-адресов, которые упрощают отображение данных в виде форм и списков для пользователя.
Чтобы объяснить, как RESTful работает с TurboGears, мы собираемся определить простой веб-сервис, который предоставляет список студентов.
Код для модели студента приведен ниже -
модель \ student.py
# -* - coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.orm import mapper, relation, relation, backref
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Integer, Unicode, DateTime
from hello.model import DeclarativeBase, metadata, DBSession
from datetime import datetime
class student(DeclarativeBase):
__tablename__ = 'student'
uid = Column(Integer, primary_key = True)
name = Column(Unicode(20), nullable = False, default = '')
city = Column(Unicode(20), nullable = False, default = '')
address = Column(Unicode(100), nullable = False, default = '')
pincode = Column(Unicode(10), nullable = False, default = '')
Теперь создайте контроллер на основе RestController и предоставьте функцию просмотра для вывода списка студентов в формате json.
Контроллеры \ student.py
from tg import RestController
from tg import expose
from hello import model
from hello.model import DBSession
from hello.model.student import student
from tg.decorators import with_trailing_slash
class StudentController(RestController):
@expose('json')
def get_all(self):
students = DBSession.query(student).all()
return dict(students=students)
Установите этот StudentController в RootController приложения, включив следующие строки в root.py -
from hello.controllers.student import StudentController
class RootController(BaseController):
students = StudentController()
Собираться в http://localhost:8080/students он предоставит список наших студентов в формате json.
Мы используем метод публикации, чтобы определить, как мы собираемся сохранить нашего ученика в базе данных. Этот метод вызывается всякий раз, когда http://localhost:8080/student URL-адрес доступен с помощью запроса POST -
@expose('json')
def post(self, name, city, address, pincode):
newstudent = student(name = name, city = city, address = address, pincode = pincode)
DBSession.add(newstudent)
DBSession.flush()
return dict(student = newstudent)
Используя get_one() метод, мы можем отобразить один элемент из базы данных пользователю -
@expose('json')
def get_one(self, movie_id):
newstudent = DBSession.query(student).get(uid)
return dict(movie = movie)
PUT - это метод, используемый для обновления существующей записи с помощью REST -
@expose('json')
def put(self, name = name, city = city, address = address, pincode = pincode, **kw):
newstudent = DBSession.query(student).get(name)
newstudent.name = name
newstudent.city = city
newstudent.address = address
newstudent.pincode = pincode
return dict(student = newstudent)
К методу post_delete прикреплена рабочая лошадка удаления. Здесь мы фактически удаляем запись из базы данных, а затем перенаправляем обратно на страницу со списком -
@expose('json')
def post_delete(self, uid, **kw):
newstudent = DBSession.query(student).get(uid)
DBSession.delete(newstudent)
return dict(movie = newstudent.uid)
Чтобы перейти от среды разработки к полноценной производственной среде, приложение необходимо развернуть на реальном веб-сервере. В зависимости от того, что у вас есть, доступны разные варианты развертывания веб-приложения TurboGears.
Apache с mod_wsgi
Mod_wsgi - это модуль Apache, разработанный Грэмом Дамплтоном. Он позволяет обслуживать программы WSGI с помощью веб-сервера Apache.
Во-первых, установите Apache 2.X для своей платформы, если это еще не сделано. После установки Apache установите mod_wsgi. Создайте и активируйте виртуальную среду Python на сервере и установите в нее TurboGears.
Установите свое приложение в директоре приложений, затем создайте сценарий с именем app.wsgi.
Настройте установку Apache следующим образом -
<VirtualHost *:80>
ServerName www.site1.com
WSGIProcessGroup www.site1.com
WSGIDaemonProcess www.site1.com user = <username>
group = www-data threads = 4 python-path = <pythonpath>
WSGIScriptAlias myapp/app.wsgi
#Serve static files directly without TurboGears
Alias /images
Alias /css
Alias /js
CustomLog
ErrorLog
</VirtualHost>
Перезагрузите Apache
Тип http://www.site1.com/ в браузере, чтобы получить доступ к приложению.
TurboGears под Circus and Chaussette
Цирк - это менеджер процессов и сокетов. Его можно использовать для мониторинга и управления процессами и сокетами. В сочетании с сервером Chaussette WSGI он может стать мощным инструментом для развертывания вашего приложения и управления любым связанным процессом, который нужен вашим приложениям.
TurboGears - GoogleAppEngine
Установите SDK Google AppEngine для Python со следующего URL-адреса - https://cloud.google.coms
Установите Google AppEngine в свою систему. Затем откройте консоль разработчика Google и войдите в свою учетную запись Google -https://console.developers.google.com/start
Создайте новый проект под названием mytgapp -
Используя Google AppEngine Launcher, создайте новое приложение с именем mytgapp.
Следующие файлы будут созданы в указанном каталоге -
- app.yaml
- favicon.ico
- index.yaml
- main.py
По умолчанию созданное приложение использует фреймворк Webapp2. Чтобы удалить эту зависимость, отредактируйте файл app.yaml и удалите следующую часть -
libraries:
- name: webapp2
version: "2.5.2"
Создайте временную виртуальную среду в каталоге с именем mytgapp и установите TurboGears. Создайте в нем приложение TurboGears. Теперь мы можем продолжить редактированиеmain.py файл, который запускается AppEngine для запуска нашего приложения и написания туда приложения TurboGears.
Добавьте следующее содержимое в main.py -
import os
import site
site.addsitedir(os.path.join(os.path.dirname(__file__), 'packages'))
from tg import expose, TGController, AppConfig
class RootController(TGController):
@expose()
def index(self):
return "<h1>Hello World</h1>"
config = AppConfig(minimal = True, root_controller = RootController())
app = config.make_wsgi_app()
Теперь запустите приложение из AppEngine Launcher и нажмите кнопку обзора, чтобы убедиться, что приложение правильно работает на локальном хосте.
Мы уже создали проект mytgapp в консоли разработчика. Теперь нажмите кнопку развертывания в панели запуска. После завершения процесса развертыванияhttp://mytgapp.appspot.com/ посетите, чтобы просмотреть нашу заявку в Интернете.