Ural penguins - Сообщения с тегом traversal
http://uralbash.ru/blog/tag/traversal/atom.xml
2016-05-31T14:49:00Z
ABlog
REST API в Pyramid
http://uralbash.ru/articles/2016/pyramid-restapi/
2016-05-31T14:49:00Z
2016-05-31T14:49:00Z
Uralbash
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.1.rest.html">http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.1.rest.html</a></p>
</div>
<div class="section" id="rest-api-pyramid">
<div class="section" id="rest-api">
<h2>REST API</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="https://ru.wikipedia.org/wiki/REST">https://ru.wikipedia.org/wiki/REST</a></li>
<li><a class="reference external" href="http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html">Для тех кто в Djang’е
(http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html)</a></li>
<li><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/testing/testing_post_curl.html">http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/testing/testing_post_curl.html</a></li>
</ul>
</div>
<p><code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code> подразумевает под собой простые правила:</p>
<ul class="simple">
<li>Каждый URL является ресурсом</li>
<li>При обращении к ресурсу методом <code class="docutils literal"><span class="pre">GET</span></code> возвращается описание этого
ресурса</li>
<li>Метод <code class="docutils literal"><span class="pre">POST</span></code> добавляет новый ресурс</li>
<li>Метод <code class="docutils literal"><span class="pre">PUT</span></code> изменяет ресурс</li>
<li>Метод <code class="docutils literal"><span class="pre">DELETE</span></code> удаляет ресурс</li>
</ul>
<p>Эти правила предоставляют простой <code class="docutils literal"><span class="pre">CRUD</span></code> интерфейс для других приложений,
взаимодействие с которым происходит через протокол <code class="docutils literal"><span class="pre">HTTP</span></code>.</p>
<p>Соответствие <code class="docutils literal"><span class="pre">CRUD</span></code> операций и <code class="docutils literal"><span class="pre">HTTP</span></code> методов:</p>
<ul class="simple">
<li><strong>CREATE</strong> - <code class="docutils literal"><span class="pre">POST</span></code></li>
<li><strong>READ</strong> - <code class="docutils literal"><span class="pre">GET</span></code></li>
<li><strong>UPDATE</strong> - <code class="docutils literal"><span class="pre">PUT</span></code></li>
<li><strong>DELETE</strong> - <code class="docutils literal"><span class="pre">DELETE</span></code></li>
</ul>
<p><code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code> интерфейс очень удобен для межпрограммного взаимодействия,
например мобильное приложение может выступать в роли клиента, который
манипулирует данными посредством <code class="docutils literal"><span class="pre">REST</span></code>.</p>
<div class="section" id="pattern-matching">
<h3>Pattern matching</h3>
<p>Пример выше добавляет View с тремя методами, каждый из которых вызывается при
соответствующем <code class="docutils literal"><span class="pre">GET</span></code>, <code class="docutils literal"><span class="pre">POST</span></code>, <code class="docutils literal"><span class="pre">DELETE</span></code> запросе.
Ресурсом здесь является конкретный человек, получить которого можно по URL
<a class="reference external" href="http://localhost:8080/api/v1/people/123">http://localhost:8080/api/v1/people/123</a></p>
<p>Результатом запроса будет:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"get"</span><span class="p">:</span> <span class="p">{},</span> <span class="nt">"id"</span><span class="p">:</span> <span class="s2">"123"</span><span class="p">,</span> <span class="nt">"method"</span><span class="p">:</span> <span class="s2">"GET"</span><span class="p">}</span>
</pre></div>
</div>
<p>Для отправки <code class="docutils literal"><span class="pre">POST</span></code> запроса воспользуемся консольной утилитой <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=curl">curl</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X POST -d <span class="s1">'param1=value1&param2=value2'</span> http://localhost:8080/api/v1/people/1
</pre></div>
</div>
<p>Результат запроса:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"id"</span><span class="p">:</span> <span class="s2">"1"</span><span class="p">,</span> <span class="nt">"post"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"param1"</span><span class="p">:</span> <span class="s2">"value1"</span><span class="p">,</span> <span class="nt">"param2"</span><span class="p">:</span> <span class="s2">"value2"</span><span class="p">},</span> <span class="nt">"method"</span><span class="p">:</span> <span class="s2">"POST"</span><span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">DELETE</span></code> запрос выполняется по аналогии:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X DELETE http://localhost:8080/api/v1/people/1
</pre></div>
</div>
<p>Результат запроса:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="traversal">
<h3>Traversal</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last">Метод URL диспетчеризации <a class="reference internal" href="../../../articles/2016/pyramid-traversal/#traversal-routing"><span class="std std-ref">Traversal</span></a></p>
</div>
<p>В предыдущем примере показан только один ресурс - конкретный человек и
в принципе все выглядит неплохо, пока не появится другой смежный ресурс,
например список всех людей по адресу <a class="reference external" href="http://localhost:8080/api/v1/people">http://localhost:8080/api/v1/people</a></p>
<p>В этом случае, придется добавлять новый путь (rout), привязывать его к
представлению (View) и самое неприятное менять само представление, или еще
хуже писать новое. Таким образом с увеличением ресурсов, сложность REST API
растет не пропорционально и в какой то момент код становится не читаемым
из-за больших размеров и постоянно меняющейся логики во View.</p>
<p>Выход из данной ситуации - отделить ресурсы от представлений, тем самым
вынести часть логики и сделать представления более универсальными.</p>
<div class="section" id="id1">
<h4>Ресурсы</h4>
<p>Ресурсы могут выглядеть так:</p>
<p><code class="docutils literal"><span class="pre">PeopleResource</span></code> представляет список всех людей и будет доступен по
адресу <a class="reference external" href="http://localhost:8080/api/v1/people">http://localhost:8080/api/v1/people</a>.
<code class="docutils literal"><span class="pre">PeopleResource</span></code> имеет метод <code class="docutils literal"><span class="pre">__getitem__</span></code>, что делает его похожим на
словарь. При обращении к объекту ресурса как к словарю, он вызовет
эту функцию и передаст ключ в параметр <code class="docutils literal"><span class="pre">people_id</span></code>, например:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">foo</span> <span class="o">=</span> <span class="n">PeopleResource</span><span class="p">()</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span><span class="p">[</span><span class="mi">123</span><span class="p">]</span> <span class="c1"># Вернет объект PersonResource(123)</span>
</pre></div>
</div>
<p>Метод <code class="docutils literal"><span class="pre">__json__</span></code> определяет каким образом преобразовывать ресурс в json.</p>
<p><code class="docutils literal"><span class="pre">PersonResource</span></code> представляет конкретного человека и будет доступен по
адресу <a class="reference external" href="http://localhost:8080/api/v1/people/{id}">http://localhost:8080/api/v1/people/{id}</a>. Здесь отличительной
особенностью является то, что метод <code class="docutils literal"><span class="pre">__json__</span></code> наследует часть словаря из
класса <code class="docutils literal"><span class="pre">PeopleResource</span></code>, при помощи конструкции <code class="docutils literal"><span class="pre">super</span></code>:</p>
</div>
<div class="section" id="view">
<h4>View</h4>
<p>Перепишем View таким образом, что бы она возвращала только ресурс, а так-как
ресурс уже содержит в себе информацию как отдавать json, то это представление
будет универсальным как для <code class="docutils literal"><span class="pre">PeopleResource</span></code>, так и для <code class="docutils literal"><span class="pre">PersonResource</span></code>
и возможно подойдет другим ресурсам которые мы будем писать в будущем.</p>
<p>Рендерер <code class="docutils literal"><span class="pre">json</span></code> по умолчанию ищет метод <code class="docutils literal"><span class="pre">__json__</span></code> и если он есть то
возвращает его результат вызова.</p>
</div>
<div class="section" id="route">
<h4>Route</h4>
<p>Путь, в нашем случае, будет один, так-как вся структура вынесена в ресурсы
(метод <code class="docutils literal"><span class="pre">__getitem__</span></code>).</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'rest_api'</span><span class="p">,</span> <span class="s1">'/api/v1/*traverse'</span><span class="p">,</span> <span class="n">factory</span><span class="o">=</span><span class="n">rest_factory</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="id2">
<h4>Полный пример</h4>
</div>
</div>
</div>
</div>
Traversal роутинг в Pyramid
http://uralbash.ru/articles/2016/pyramid-traversal/
2016-05-30T14:49:00Z
2016-05-30T14:49:00Z
Uralbash
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.urldispatch.html">http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.urldispatch.html</a></p>
</div>
<div class="section" id="traversal-pyramid">
<div class="section" id="url">
<h2>Диспетчеризация URL</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid/en/1.6-branch/narr/urldispatch.html">http://docs.pylonsproject.org/projects/pyramid/en/1.6-branch/narr/urldispatch.html</a></li>
<li><a class="reference external" href="http://pyramid-cookbook.readthedocs.org/en/latest/routing/index.html">http://pyramid-cookbook.readthedocs.org/en/latest/routing/index.html</a></li>
<li><a class="reference external" href="http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html">Для тех кто в Djang’е
(http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html)</a></li>
</ul>
</div>
<p>Каждый поступающий на сервер приложений Pyramid запрос (<strong>request</strong>) должен
найти вид (<strong>view</strong>), который и будет его обрабатывать.</p>
<p>В Pyramid имеется два базовых подхода к поиску нужного вида для обрабатываемого
запроса: на основе сопоставления (<strong>matching</strong>), как в большинстве подобных
фреймворков, и обхода (<strong>traversal</strong>), как в <a class="reference external" href="http://www.zope.org/">Zope</a>. Кроме того, в одном
приложении можно с успехом сочетать оба подхода.</p>
<div class="section" id="pattern-matching">
<h3>Pattern Matching</h3>
<p>Простейший пример с заданием маршрута (заимствован из документации):</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># Здесь config - экземпляр pyramid.config.Configurator</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'idea'</span><span class="p">,</span> <span class="s1">'site/{id}'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="s1">'mypackage.views.site_view'</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'idea'</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="traversal">
<span id="traversal-routing"></span><h3>Traversal</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/traversal.html">http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/traversal.html</a></li>
</ul>
</div>
<p>Использование обхода лучше проиллюстрировать на небольшом примере:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">wsgiref.simple_server</span> <span class="kn">import</span> <span class="n">make_server</span>
<span class="kn">from</span> <span class="nn">pyramid.config</span> <span class="kn">import</span> <span class="n">Configurator</span>
<span class="kn">from</span> <span class="nn">pyramid.response</span> <span class="kn">import</span> <span class="n">Response</span>
<span class="c1"># Класс некоторого ресурса</span>
<span class="k">class</span> <span class="nc">Resource</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">pass</span>
<span class="c1"># Дерево ресурсов (жёстко закодированное) в фабрике корня</span>
<span class="k">def</span> <span class="nf">get_root</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Resource</span><span class="p">({</span><span class="s1">'a'</span><span class="p">:</span> <span class="n">Resource</span><span class="p">({</span><span class="s1">'b'</span><span class="p">:</span> <span class="n">Resource</span><span class="p">({</span><span class="s1">'c'</span><span class="p">:</span> <span class="n">Resource</span><span class="p">()})})})</span>
<span class="c1"># Вид-для-вызова, который умеет показывать ресурс Resource (в context)</span>
<span class="k">def</span> <span class="nf">hello_world_of_resources</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="n">output</span> <span class="o">=</span> <span class="s2">"Ресурс и его дети: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">context</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">Configurator</span><span class="p">(</span><span class="n">root_factory</span><span class="o">=</span><span class="n">get_root</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">hello_world_of_resources</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">Resource</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">make_server</span><span class="p">(</span><span class="s1">'0.0.0.0'</span><span class="p">,</span> <span class="mi">8080</span><span class="p">,</span> <span class="n">app</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
</pre></div>
</div>
<p>В этом примере иерархия для обхода жестко задана в методе <code class="docutils literal"><span class="pre">get_root</span></code> с
помощью вложенных словарей, тогда как реальные приложения должны сами
определять необходимый доступ по ключам (метод <code class="docutils literal"><span class="pre">__getitem__</span></code> помогает
организовать такой доступ). В коде также присутствует корневая фабрика, с
которой собственно и начинается обход узлов (node) дерева ресурсов.
Вид-для-вызова (<a class="reference external" href="https://docs.pylonsproject.org/projects/pyramid/en/latest/glossary.html#term-view-callable" title="(в The Pyramid Web Framework v2.0)"><span class="xref std std-term">view callable</span></a>) представлен функцией
<code class="docutils literal"><span class="pre">hello_world_of_resources</span></code>. Говоря несколько упрощённо, на основе URL запроса
в результате обхода иерархии Pyramid находит ресурс и применяет к нему
«наилучший» вид-для-вызова (в нашем примере — он единственный).</p>
<div class="section" id="id1">
<h4>Обход словаря</h4>
<div class="admonition warning">
<p class="first admonition-title">Предупреждение</p>
<p class="last">В примерах используется Python3</p>
</div>
<p>Метод обхода дерева (traversal), позволяет находить ресурсы во вложенных структурах.
Такой механизм хорошо применим для некоторых практических задач, например
список всех URL маршрутов сайта является деревом, в котором каждый конечный URL
это отдельная ветка дерева. Поэтому всю структуру сайта можно поместить в словарь.</p>
<p>К примеру, известно, что смерь сказочного персонажа “кащея” находится в яйце,
которое в свою очередь в утке, которая в зайце и т.д. В сумме получается
вложенная структура, которую можно описать так:</p>
<p><code class="docutils literal"><span class="pre">остров</span> <span class="pre">-></span> <span class="pre">дуб</span> <span class="pre">-></span> <span class="pre">сундук</span> <span class="pre">-></span> <span class="pre">заяц</span> <span class="pre">-></span> <span class="pre">утка</span> <span class="pre">-></span> <span class="pre">яйцо</span> <span class="pre">-></span> <span class="pre">игла</span> <span class="pre">-></span> <span class="pre">СмертьКощея</span></code></p>
<p>Мы можем такую, плоскую, вложенную структуру легко представить в виде URL:</p>
<p><code class="docutils literal"><span class="pre">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</span></code></p>
<p>А так-как любой URL является веткой дерева, то несложно описать это в Python:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="s1">'остров'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'дуб'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'сундук'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'заяц'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'утка'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'яйцо'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'игла'</span><span class="p">:</span> <span class="n">СмертьКощея</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">СмертьКощея()</span></code> - это объект класса <code class="docutils literal"><span class="pre">СмертьКощея</span></code>, который может выглядеть к примеру так:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">СмертьКощея</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__json__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">'имя'</span><span class="p">:</span> <span class="s1">'кощей'</span><span class="p">,</span>
<span class="s1">'статус'</span><span class="p">:</span> <span class="n">request</span><span class="o">.</span><span class="n">context</span> <span class="o">==</span> <span class="bp">self</span> <span class="ow">and</span> <span class="s1">'мертв'</span> <span class="ow">or</span> <span class="s1">'жив ещё'</span><span class="p">,</span>
<span class="p">}</span>
</pre></div>
</div>
<p>В принципе, этого достаточно что бы наш сайт-убийца “кощея” заработал.
Осталось лишь прописать пути и добавить представление (view).</p>
<p>View будет просто возвращать объект, например, если мы ввели:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров'
объект: {'дуб': {
'сундук': {
'заяц': {
'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}
}
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб'
объект: {'сундук': {
'заяц': {
'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук'
объект: {'заяц': {
'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц'
объект: {'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц/утка'
объект: {'яйцо': {
'игла': СмертьКощея()
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц/утка/яйцо'
объект: {'игла': СмертьКощея()}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц/утка/яйцо/игла'
объект: СмертьКощея()
</pre></div>
</div>
<p>Такие функции-представления (View) должны принимать 2 параметра, где первый
параметр будет являться объектом, обычно именуемым <code class="docutils literal"><span class="pre">context</span></code>, а второй
параметр <code class="docutils literal"><span class="pre">request</span></code>:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">traverse_koshey</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">context</span> <span class="c1"># Наш объект</span>
</pre></div>
</div>
<p>Роуты создаются почти так же как в <code class="docutils literal"><span class="pre">pattern</span> <span class="pre">matching</span></code>, за исключением того,
что структура путей передается в виде “фабрики”, которая возвращает словарь или
ему подобный (dict-like) объект. Путь указывается в виде статической и
динамической части, например <code class="docutils literal"><span class="pre">/fixedpath/*traverse</span></code>:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'koshey'</span><span class="p">,</span> <span class="s1">'/mytraversal/*traverse'</span><span class="p">,</span> <span class="n">factory</span><span class="o">=</span><span class="n">my_factory</span><span class="p">)</span>
</pre></div>
</div>
<p>Фабрика, которая возвращает структуру сайта:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_factory</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">'остров'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'дуб'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'сундук'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'заяц'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'утка'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'яйцо'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'игла'</span><span class="p">:</span> <span class="n">СмертьКощея</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>View добавляется стандартно:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_koshey</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
</pre></div>
</div>
<p>Все готово, можно перемещаться по объектам:</p>
<ul class="simple">
<li><a class="reference external" href="http://localhost:8080/mytraversal/">http://localhost:8080/mytraversal/</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров">http://localhost:8080/mytraversal/остров</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб">http://localhost:8080/mytraversal/остров/дуб</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук">http://localhost:8080/mytraversal/остров/дуб/сундук</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</a></li>
</ul>
<p>Полный пример:</p>
<p>Есть один нюанс, json renderer, по умолчанию, все не латинские символы отображает
как UTF коды <code class="docutils literal"><span class="pre">\uxxxx</span></code>, поэтому мы увидим следующий вывод:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"\u043e\u0441\u0442\u0440\u043e\u0432"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0434\u0443\u0431"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0441\u0443\u043d\u0434\u0443\u043a"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0437\u0430\u044f\u0446"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0443\u0442\u043a\u0430"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u044f\u0439\u0446\u043e"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0438\u0433\u043b\u0430"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0441\u0442\u0430\u0442\u0443\u0441"</span><span class="p">:</span> <span class="s2">"\u0436\u0438\u0432 \u0435\u0449\u0451"</span><span class="p">,</span> <span class="nt">"\u0438\u043c\u044f"</span><span class="p">:</span> <span class="s2">"\u043a\u043e\u0449\u0435\u0439"</span><span class="p">}}}}}}}}</span>
</pre></div>
</div>
<p>Но можно изменить его поведение следующим образом:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">pyramid.renderers</span> <span class="k">import</span> <span class="n">JSON</span>
<span class="o">...</span>
<span class="hll"> <span class="n">config</span><span class="o">.</span><span class="n">add_renderer</span><span class="p">(</span><span class="s1">'myjson'</span><span class="p">,</span> <span class="n">JSON</span><span class="p">(</span><span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">))</span>
</span> <span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_koshey</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'myjson'</span><span class="p">)</span>
</pre></div>
</div>
<p>Результат:</p>
<p><a class="reference external" href="http://localhost:8080/mytraversal/">http://localhost:8080/mytraversal/</a></p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"остров"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"дуб"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"сундук"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"заяц"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"утка"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"яйцо"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"игла"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"имя"</span><span class="p">:</span> <span class="s2">"кощей"</span><span class="p">,</span>
<span class="nt">"статус"</span><span class="p">:</span> <span class="s2">"жив ещё"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</a></p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"имя"</span><span class="p">:</span> <span class="s2">"кощей"</span><span class="p">,</span>
<span class="nt">"статус"</span><span class="p">:</span> <span class="s2">"мертв"</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Полный код:</p>
</div>
<div class="section" id="view">
<h4>Привязка View к ресурсам</h4>
<p>В Пирамиде объект (context) который передается во вью, именуют еще как “ресурс”.
Есть возможность жестко привязать View к типу ресурса. Например, наше
представление <code class="docutils literal"><span class="pre">traverse_koshey</span></code> должно вызываться, только когда пришел объект
класса <code class="docutils literal"><span class="pre">СмертьКощея</span></code>:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_koshey</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey_context'</span><span class="p">,</span>
<span class="n">renderer</span><span class="o">=</span><span class="s1">'myjson'</span><span class="p">,</span>
<span class="hll"> <span class="n">context</span><span class="o">=</span><span class="n">СмертьКощея</span><span class="p">)</span>
</span></pre></div>
</div>
<p>Параметр <code class="docutils literal"><span class="pre">context</span></code> указывает на то, что это View принадлежит ТОЛЬКО объектам
класса <code class="docutils literal"><span class="pre">СмертьКащея</span></code>.</p>
<p>Все пути, кроме полного (который возвращает нужный объект), вернут 404 код ответа.
Полный путь <a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</a>.</p>
<p>Добавим в нашу структуру еще ресурсов:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_factory</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">'превед'</span><span class="p">:</span> <span class="n">Человек</span><span class="p">(),</span>
<span class="s1">'остров'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'ясень'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'что то здесь'</span><span class="p">:</span> <span class="s1">'не так!'</span>
<span class="p">},</span>
<span class="s1">'дуб'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'сундук'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'заяц'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'утка'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'яйцо'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'игла'</span><span class="p">:</span> <span class="n">СмертьКощея</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Здесь <code class="docutils literal"><span class="pre">Человек()</span></code> это новый тип ресурса, который имеет метод <code class="docutils literal"><span class="pre">__getitem__</span></code>
как у словаря и при обращении по ключу возвращает другой ресурс:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Человек</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'Человек'</span>
<span class="k">def</span> <span class="nf">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Имя</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Имя</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="n">__parent__</span> <span class="o">=</span> <span class="n">Человек</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
</pre></div>
</div>
<p>Например мы обращаемся по URL <a class="reference external" href="http://localhost:8080/mytraversal/превед/Пирамид">http://localhost:8080/mytraversal/превед/Пирамид</a>.
<code class="docutils literal"><span class="pre">превед</span></code> вернет ресурс <code class="docutils literal"><span class="pre">Человек</span></code>, а <code class="docutils literal"><span class="pre">Пирамид</span></code> вызовет метод
<code class="docutils literal"><span class="pre">__getitem__</span></code>, который вернет ресурс <code class="docutils literal"><span class="pre">Имя('Пирамид')</span></code>. Таким образом мы
можем строить дерево динамически при помощи dict-like объектов.</p>
<p>Для ресурса <code class="docutils literal"><span class="pre">Имя</span></code> мы можем создать отдельное представление и жестко привязать
его к этому типу.</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">traverse_hello</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> http://localhost:8080/mytraversal/первед/Пирамид</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="s1">'Превед '</span> <span class="o">+</span> <span class="n">context</span><span class="o">.</span><span class="n">__parent__</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="n">context</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="o">...</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_hello</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey_context'</span><span class="p">,</span>
<span class="n">renderer</span><span class="o">=</span><span class="s1">'text'</span><span class="p">,</span>
<span class="n">context</span><span class="o">=</span><span class="n">Имя</span><span class="p">)</span>
</pre></div>
</div>
<p>Результат вывода по адресу
<a class="reference external" href="http://localhost:8080/mytraversal/превед/Пирамид">http://localhost:8080/mytraversal/превед/Пирамид</a>, будет обычный текст
(<code class="docutils literal"><span class="pre">Content-Type:</span> <span class="pre">plain/text</span></code>):</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>Превед Человек Пирамид
</pre></div>
</div>
<p>Полный пример:</p>
</div>
</div>
<div class="section" id="id14">
<h3>Комбинация обоих методов</h3>
<p>Фреймворк <code class="docutils literal"><span class="pre">Pyramid</span></code> позволяет использовать оба способа URL маршрутизации
одновременно.</p>
<p>Добавим к примеру с “кащеем” hello world с использованием pattern matching:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hello_world</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="s1">'Hello </span><span class="si">%(name)s</span><span class="s1">!'</span> <span class="o">%</span> <span class="n">request</span><span class="o">.</span><span class="n">matchdict</span><span class="p">)</span>
<span class="o">...</span>
<span class="c1"># Pattern matching routes</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'hello'</span><span class="p">,</span> <span class="s1">'/hello/</span><span class="si">{name}</span><span class="s1">'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">hello_world</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'hello'</span><span class="p">)</span>
</pre></div>
</div>
<p>Полный пример:</p>
</div>
</div>
</div>