Ural penguins - Сообщения с тегом Django
http://uralbash.ru/blog/tag/django/atom.xml
2014-03-15T17:53:00Z
ABlog
Перенос БД с sqlite на postgres
http://uralbash.ru/articles/2014/sqlite_to_pg/
2014-03-15T17:53:00Z
2014-03-15T17:53:00Z
Uralbash
<div class="section" id="sqlite-postgres">
<p><code class="docutils literal"><span class="pre">ORM</span></code> позволяет быстро переключатся между БД не учитывая их диалект
(практически). Но данные хранятся физически в разных местах и естественно их
надо переносить, например при переключении с <a class="reference external" href="http://sqlite.org/">sqlite</a> на <a class="reference external" href="http://postgresql.org">PostgreSQL</a>. В
<a class="reference external" href="https://www.djangoproject.com/">Django</a> есть встроенный функционал в виде:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Выгрузка в JSON</span>
$ python manage.py dumpdata myapp.A > a.json
<span class="c1"># Загрузка из JSON</span>
$ python manage.py loaddata a.json
</pre></div>
</div>
<p>Т.е. мы выгружаем данные из <a class="reference external" href="http://sqlite.org/">sqlite</a> в <code class="docutils literal"><span class="pre">JSON</span></code> формат, затем меняем строку
подключения на <a class="reference external" href="http://postgresql.org">postgres</a> и выполняем загрузку из <code class="docutils literal"><span class="pre">JSON</span></code>. Очень удобно, но
почему то этот метод не работает, либо работает только при переносе из <code class="docutils literal"><span class="pre">sqlite</span>
<span class="pre">-></span> <span class="pre">sqlite</span></code>, что в принципе не очень интересно, точнее бессмысленно. Есть какие
то решений с бубном как это вот:</p>
<div class="line-block">
<div class="line"><a class="reference external" href="http://macrotoma.blogspot.ru/2012/10/solved-move-django-from-sqlite-to-mysql.html">http://macrotoma.blogspot.ru/2012/10/solved-move-django-from-sqlite-to-mysql.html</a>,</div>
<div class="line"><a class="reference external" href="http://blog.abourget.net/2009/7/7/exporting-sql-schemas-from-sqlalchemy-table-definitions/">http://blog.abourget.net/2009/7/7/exporting-sql-schemas-from-sqlalchemy-table-definitions/</a>.</div>
</div>
<p>Эти методы не универсальны, потому что имеют привязку к моделям (ORM), требуют
для переноса проект на <a class="reference external" href="https://www.djangoproject.com/">Django</a> и ручные действия вроде создания схемы и
выполнения миграций (далеко не всегда миграции созданы правильно).</p>
<p>Я написал небольшой пример как можно перевести данные не имея фреймворков, не
привязываясь к моделям, указав только две строки подключения откуда переносить
и куда (вроде было что то похожее на руби). За основы взят пример из этой статьи
<a class="reference external" href="http://www.tylerlesmann.com/2009/apr/27/copying-databases-across-platforms-sqlalchemy/">http://www.tylerlesmann.com/2009/apr/27/copying-databases-across-platforms-sqlalchemy/</a>.
Где предлагается указать дополнительно названия таблиц.</p>
<p>В <a class="reference external" href="http://sqlalchemy.org/">sqlalchemy</a> с весии 9.1 появилась встроенная возможность автоматического
определения схемы БД
<a class="reference external" href="http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/automap.html">http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/automap.html</a>. Правда
намного раньше появились сторонние решения:</p>
<ul class="simple">
<li><a class="reference external" href="http://turbogears.org/2.1/docs/main/Utilities/sqlautocode.html">http://turbogears.org/2.1/docs/main/Utilities/sqlautocode.html</a></li>
<li><a class="reference external" href="https://sqlsoup.readthedocs.org/en/latest/">https://sqlsoup.readthedocs.org/en/latest/</a>.</li>
</ul>
<p>Первое что мы сделаем, это получим схему БД:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy.ext.automap</span> <span class="kn">import</span> <span class="n">automap_base</span>
<span class="k">def</span> <span class="nf">get_metadata</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">engine</span><span class="p">):</span>
<span class="c1"># produce our own MetaData object</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span>
<span class="c1"># we can reflect it ourselves from a database, using options</span>
<span class="c1"># such as 'only' to limit what tables we look at...</span>
<span class="c1"># only = ['news_news', 'pages_page']</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">only</span><span class="p">:</span>
<span class="n">metadata</span><span class="o">.</span><span class="n">reflect</span><span class="p">(</span><span class="n">engine</span><span class="p">,</span> <span class="n">only</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">only</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">metadata</span><span class="o">.</span><span class="n">reflect</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="c1"># we can then produce a set of mappings from this MetaData.</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">automap_base</span><span class="p">(</span><span class="n">metadata</span><span class="o">=</span><span class="n">metadata</span><span class="p">)</span>
<span class="c1"># calling prepare() just sets up mapped classes and relationships.</span>
<span class="n">Base</span><span class="o">.</span><span class="n">prepare</span><span class="p">()</span>
<span class="k">return</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">Base</span>
</pre></div>
</div>
<p>Дальше получаем все таблицы:</p>
<p><code class="docutils literal"><span class="pre">tables</span> <span class="pre">=</span> <span class="pre">Base.classes</span></code></p>
<p>Создаем такую же структуру БД в <a class="reference external" href="http://postgresql.org">postgres</a>:</p>
<p><code class="docutils literal"><span class="pre">metadata.create_all(self.engine_dst)</span></code></p>
<p>По очереди проходим каждую таблицу и переносим из нее данные в новую БД:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">table</span> <span class="ow">in</span> <span class="n">tables</span><span class="p">:</span>
<span class="n">columns</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
<span class="k">print</span> <span class="s1">'Transferring records to </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">name</span>
<span class="k">for</span> <span class="n">record</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">table</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="n">data</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
<span class="p">[(</span><span class="nb">str</span><span class="p">(</span><span class="n">column</span><span class="p">),</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">record</span><span class="p">,</span> <span class="n">column</span><span class="p">))</span> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span><span class="p">]</span>
<span class="p">)</span>
<span class="n">NewRecord</span> <span class="o">=</span> <span class="n">quick_mapper</span><span class="p">(</span><span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session_dst</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">NewRecord</span><span class="p">(</span><span class="o">**</span><span class="n">data</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session_dst</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</pre></div>
</div>
<p>Если возникли конфликты можно их решить переопределением типов полей. Например
при переносе из <a class="reference external" href="http://sqlite.org/">sqlite</a> в <a class="reference external" href="http://postgresql.org">postgres</a> тип полей <code class="docutils literal"><span class="pre">DATETIME</span></code> нужно
заменить на <code class="docutils literal"><span class="pre">DateTime</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">dialect</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">engine</span><span class="o">.</span><span class="n">dialect</span><span class="o">.</span><span class="n">name</span>
<span class="n">dialect_dst</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">engine_dst</span><span class="o">.</span><span class="n">dialect</span><span class="o">.</span><span class="n">name</span>
<span class="k">if</span> <span class="n">dialect</span> <span class="o">==</span> <span class="n">dialect_dst</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">table</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tables</span><span class="p">:</span>
<span class="n">columns</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">c</span>
<span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span><span class="p">:</span>
<span class="k">if</span> <span class="n">dialect_dst</span> <span class="o">==</span> <span class="s1">'postgresql'</span><span class="p">:</span>
<span class="c1"># DATETIME->DateTime</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">column</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="n">DATETIME</span><span class="p">):</span>
<span class="n">column</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">DateTime</span><span class="p">()</span>
</pre></div>
</div>
<p>Пример запуска:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ python convertdbdata.py -f <span class="s2">"sqlite:///fromMydb.sqlite"</span> -t <span class="s2">"postgresql://postgres:postgres@localhost/toMydb"</span> -i <span class="s2">"auth_user,news_news"</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">-i</span></code> параметр указывает какие таблицы нужно запускать первыми, например в такой ситуации:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>DETAIL: Ключ <span class="o">(</span>user_id<span class="o">)=(</span><span class="m">1</span><span class="o">)</span> отсутствует в таблице <span class="s2">"auth_user"</span>.
<span class="s1">'INSERT INTO django_admin_log (id, action_time, user_id, content_type_id, object_id, object_repr, action_flag,</span>
<span class="s1"> change_message) VALUES (%(id)s, %(action_time)s, %(user_id)s, %(content_type_id)s, %(object_id)s, %(object_repr)s,</span>
<span class="s1"> %(action_flag)s, %(change_message)s)'</span> <span class="o">{</span><span class="s1">'action_flag'</span>: <span class="m">1</span>, <span class="s1">'action_time'</span>: datetime.datetime<span class="o">(</span><span class="m">2014</span>, <span class="m">2</span>, <span class="m">5</span>, <span class="m">13</span>, <span class="m">15</span>, <span class="m">27</span>, <span class="m">948000</span><span class="o">)</span>,
<span class="s1">'user_id'</span>: <span class="m">1</span>, <span class="s1">'content_type_id'</span>: <span class="m">39</span>, <span class="s1">'object_repr'</span>: u<span class="s1">'dfgsdfg'</span>, <span class="s1">'object_id'</span>: u<span class="s1">'1'</span>, <span class="s1">'change_message'</span>: u<span class="s1">''</span>, <span class="s1">'id'</span>: <span class="m">1</span><span class="o">}</span>
</pre></div>
</div>
<p>Код полностью <a class="reference external" href="https://github.com/ITCase/convertdbdata">https://github.com/ITCase/convertdbdata</a></p>
<p>Сейчас скрипт не рассчитан на большие объемы данных и учитывает только разницу
в <code class="docutils literal"><span class="pre">DateTime</span></code> поле, но думаю это легко исправить по мере поступления задач.</p>
</div>
Django - кот в мешке.
http://uralbash.ru/articles/2014/django-hyango/
2014-02-02T20:43:00Z
2014-02-02T20:43:00Z
Uralbash
<div class="section" id="django">
<img alt="_static/2014/wat.jpg" class="align-right" src="_static/2014/wat.jpg" style="width: 420px;" />
<p><a class="reference external" href="https://www.djangoproject.com/">Django</a> это фреймворк, при помощи которого быстро пишутся сайты. Так ли это?</p>
<p>Фичи джанги:</p>
<ul class="simple">
<li>Админка</li>
<li>куча аппликэйшинов</li>
<li>Шаблоны</li>
<li>ORM</li>
<li>DebugToolbar</li>
</ul>
<br clear="both"/><div class="section" id="id1">
<h2>Админка</h2>
<p>Из коробки у вас есть админка. Для простых сайтов её нужно кастомайзить долго и
упорно, правда, обычно, это делается один раз. В сайте среднего уровня
жангоадминка уже не прокатит. Вывод админка даёт профит в простых сайтах.</p>
</div>
<div class="section" id="id2">
<h2>Аппликашины</h2>
<p>Обычно очень посредственного качества и не совместимы друг с другом, поэтому
танцы с бубном и велосипеды наше всё + <code class="docutils literal"><span class="pre">djangosnippets</span></code>.</p>
</div>
<div class="section" id="id3">
<h2>Шаблоны</h2>
<ul>
<li><p class="first">нету break, continue
<code class="docutils literal"><span class="pre">jinja2.ext.loopcontrols</span> <span class="pre">This</span> <span class="pre">extension</span> <span class="pre">adds</span> <span class="pre">support</span> <span class="pre">for</span> <span class="pre">break</span> <span class="pre">and</span> <span class="pre">continue</span> <span class="pre">in</span> <span class="pre">loops.</span></code></p>
</li>
<li><p class="first">рекурсия Jinja</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"sitemap"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">item</span> <span class="k">in</span> <span class="nv">sitemap</span> <span class="k">recursive</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">item.href</span><span class="o">|</span><span class="nf">e</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">item.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">item.children</span> -<span class="cp">%}</span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"submenu"</span><span class="p">></span><span class="cp">{{</span> <span class="nb">loop</span><span class="o">(</span><span class="nv">item.children</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
</pre></div>
</div>
<p>а в джанге это видимо не нужно</p>
</li>
<li><p class="first">не работает вызов функций типа <code class="docutils literal"><span class="pre">item()</span></code> (лолшто?)</p>
</li>
<li><p class="first"><code class="docutils literal"><span class="pre">[:-1]</span></code> не работает, нужно писать <code class="docutils literal"><span class="pre">|latest</span></code></p>
</li>
<li><p class="first"><span class="strike">для js выражение типа:</span></p>
<p><span class="strike">var foo = [{% for item in items %}{{ item.paren }}{% endfor %}]</span>
<span class="strike">не работает, потому что js выполняется до рендеринга таких {%%} конструкций.</span></p>
</li>
<li><p class="first">коменты <code class="docutils literal"><span class="pre">{#</span> <span class="pre">#}</span></code> неработают в несколько строк</p>
</li>
<li><p class="first">вместо <code class="docutils literal"><span class="pre">{{</span> <span class="pre">list[5]</span> <span class="pre">}}</span></code> -> <code class="docutils literal"><span class="pre">{{</span> <span class="pre">arr.5</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">для словарей <code class="docutils literal"><span class="pre">{{</span> <span class="pre">dict.foo</span> <span class="pre">}}</span></code> не работает, да здравствует <code class="docutils literal"><span class="pre">template</span> <span class="pre">tag</span></code></p>
</li>
<li><p class="first">для <code class="xref py py-mod docutils literal"><span class="pre">itertools.chain</span></code> можно сосать лапу с таким фокусом <code class="docutils literal"><span class="pre">{{</span> <span class="pre">list[5]</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">о джанга ты прекрасна <code class="docutils literal"><span class="pre">{{</span> <span class="pre">myval|add:"-5"</span> <span class="pre">}}</span></code> вместо уродского <code class="docutils literal"><span class="pre">{{</span> <span class="pre">myval</span> <span class="pre">-</span> <span class="pre">5</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">нельзя сделать так <code class="docutils literal"><span class="pre">{{</span> <span class="pre">dir(foo)</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">как узнать длину <a class="reference external" href="https://docs.python.org/3/library/itertools.html#module-itertools" title="(в Python v3.10)"><code class="xref py py-mod docutils literal"><span class="pre">itertools</span></code></a>? в <a class="reference external" href="http://jinja.pocoo.org/">jinja</a> делается так <code class="docutils literal"><span class="pre">{{</span> <span class="pre">list(foo).length</span> <span class="pre">}}</span></code></p>
</li>
</ul>
</div>
<div class="section" id="orm">
<h2>ORM</h2>
<ul class="simple">
<li><code class="docutils literal"><span class="pre">Page.objects.filter(parent__in=objects)</span></code> вместо <code class="docutils literal"><span class="pre">DBSession.query(Page).filter(parent</span> <span class="pre">in</span> <span class="pre">objects)</span></code></li>
<li>великолепный <code class="docutils literal"><span class="pre">foomodel_set__barmodel__name</span></code> лолшто?!</li>
<li><code class="docutils literal"><span class="pre">Entry.objects.all()[:1].get()</span></code> вместо <code class="docutils literal"><span class="pre">DBSession.query(Entry).first()</span></code> или <code class="docutils literal"><span class="pre">one()</span></code></li>
<li>добавляем в модель: <code class="docutils literal"><span class="pre">class</span> <span class="pre">Meta:</span> <span class="pre">app_label</span> <span class="pre">=</span> <span class="pre">'asdasda'</span></code> и переходим к разделу дебаг!</li>
</ul>
</div>
<div class="section" id="debug">
<h2>Debug</h2>
<style>
.red {
color: red;
font-weight: bold;
}
.red-white {
background-color: red;
font-weight: bold;
color: white;
</style><p><span class="red-white">Дебаг джанго кормит вас!</span> Потому что вы <a class="reference external" href="https://www.djangoproject.com/">Django</a> программист и
половину рабочего времени пытаетесь понять что за !@#$% произошла, получая за
это зарплату.</p>
<p><code class="docutils literal"><span class="pre">class</span> <span class="pre">Meta:</span> <span class="pre">app_label</span> <span class="pre">=</span> <span class="pre">'asdasda'</span></code> генерит трейс:</p>
<p><span class="red">django.core.management.base.CommandError: One or more models did not validate:
gallery.galleryimage: ‘gallery’ has a relation with model <class
‘gallery.models.Gallery’>, which has either not been installed or is abstract.</span></p>
<p>Шыкарные красные ошибки джанги. Очень информативно, ищется аникейством и
вспоминанием чё правил.</p>
<p>Я запилил <a class="reference external" href="https://github.com/uralbash/django-hyango">небольшой пример</a> что
бы вы могли поднять его и посмотреть на эту магию.</p>
</div>
<div class="section" id="id5">
<h2>Квик старт</h2>
<ol class="arabic">
<li><p class="first">Установка по <code class="docutils literal"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">-r</span> <span class="pre">requirements.txt</span></code></p>
</li>
<li><p class="first">Далее введим <code class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">syncdb</span></code> и видим <span class="red">ImportError: cannot import name SEOModel</span> Супер информативный вывод, все сразу стало понятно.</p>
<blockquote>
<div><p>2.1 Прошел все модели в проекте, <code class="docutils literal"><span class="pre">SEOModel</span></code> не нашел, при учете что у меня <code class="docutils literal"><span class="pre">gallery</span></code> стоит в <a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a></p>
<p>2.2 может во вью? Во вью то же нету</p>
<p>2.3 ищем по проекту тупо по всем файлам, нету.</p>
<p>2.4 идем в <code class="docutils literal"><span class="pre">settings/apps.py</span></code> и смотрим какое г может это содержать (так на угад), смотрим <code class="docutils literal"><span class="pre">common</span></code> опа вот он в моделях, осталось найти где он импортируется неправильно.</p>
<p>2.5 ради интереса запускаю сервер <code class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">runserver</span></code> и получаю:</p>
<blockquote>
<div><p><span class="red">File ”.../local/lib/python2.7/site-packages/gallery/models.py”, line 12, in <module> from website.models import SEOModel, VisibleModel ImportError: cannot import name SEOModel</span></p>
</div></blockquote>
</div></blockquote>
</li>
</ol>
<p>т.е. в некоторых случаях джангу надо дебажить runserver’ом</p>
</div>
<div class="section" id="pages">
<h2>Pages</h2>
<ul class="simple">
<li>захожу в pages в админке</li>
<li>добавляю дерево</li>
<li>тыкаю по дереву (вложенность 2го уровня) что бы развернуть список и получаю:</li>
</ul>
<p><code class="docutils literal"><span class="pre">Error</span> <span class="pre">while</span> <span class="pre">loading</span> <span class="pre">the</span> <span class="pre">data</span> <span class="pre">from</span> <span class="pre">the</span> <span class="pre">server.</span></code></p>
<img alt="_static/2014/pages_tree.png" src="_static/2014/pages_tree.png" />
<p>и трэйс:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Internal Server Error: /admin/pages/page/tree_json/
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/core/handlers/base.py"</span>, line <span class="m">115</span>, in get_response
<span class="nv">response</span> <span class="o">=</span> callback<span class="o">(</span>request, *callback_args, **callback_kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py"</span>, line <span class="m">50</span>, in wrapper
<span class="k">return</span> self.admin_site.admin_view<span class="o">(</span>view<span class="o">)(</span>*args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/utils/decorators.py"</span>, line <span class="m">91</span>, in _wrapped_view
<span class="nv">response</span> <span class="o">=</span> view_func<span class="o">(</span>request, *args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/views/decorators/cache.py"</span>, line <span class="m">89</span>, in _wrapped_view_func
<span class="nv">response</span> <span class="o">=</span> view_func<span class="o">(</span>request, *args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/contrib/admin/sites.py"</span>, line <span class="m">202</span>, in inner
<span class="k">return</span> view<span class="o">(</span>request, *args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py"</span>, line <span class="m">157</span>, in tree_json_view
<span class="nv">node</span> <span class="o">=</span> self.model.objects.get<span class="o">(</span><span class="nv">id</span><span class="o">=</span>node_id<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/db/models/manager.py"</span>, line <span class="m">143</span>, in get
<span class="k">return</span> self.get_query_set<span class="o">()</span>.get<span class="o">(</span>*args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/db/models/query.py"</span>, line <span class="m">404</span>, in get
self.model._meta.object_name<span class="o">)</span>
DoesNotExist: Page matching query does not exist.
<span class="o">[</span><span class="m">16</span>/Dec/2013 <span class="m">23</span>:42:28<span class="o">]</span> <span class="s2">"GET /admin/pages/page/tree_json/?node=5&_=1387215746550 HTTP/1.1"</span> <span class="m">500</span> <span class="m">22668</span>
</pre></div>
</div>
<div class="line-block">
<div class="line">бесполезный трейс и непонятная ошибка КРУТО!</div>
<div class="line">Если я зайду на адрес <code class="docutils literal"><span class="pre">/admin/pages/page/tree_json/?node=5&_=1387215746550</span></code></div>
</div>
<p>то получу статический trace и хер знает куда bp вставить что бы хоть за че-то
зацепиться.</p>
<p>Ставлю <a class="reference external" href="https://pypi.python.org/pypi/django-extensions">django-extensions</a> через <a class="reference external" href="https://pypi.python.org/pypi/pip">pip</a> и <a class="reference external" href="https://pypi.python.org/pypi/Werkzeug">Werkzeug</a> что бы
получить хоть какой то интерактив на том же трэйсе.</p>
<p>Запускаю командой <code class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">runserver_plus</span></code>, отваливается
<code class="docutils literal"><span class="pre">debug_toolbar</span></code>. Но и интерактивный трейс мало чем помогает в этом случае.
Джанга каким то чудом обходит то место которое все ломает, ГРЕБАННЫЙ СТЫД!
Ошибка ищется тупым эникейством. Предполагая что <a class="reference external" href="https://www.djangoproject.com/">django</a> идеальна и в ней
нет ошибок, <a class="reference external" href="https://pypi.python.org/pypi/django_mptt_admin">django_mptt_admin</a> на <code class="docutils literal"><span class="pre">example</span></code> работает хорошо, может
быть что то в Pages??? Ад же какойто?</p>
</div>
</div>
Причины названий python, django и pyramid
http://uralbash.ru/articles/2013/reason_names_of/
2013-12-22T16:34:00Z
2013-12-22T16:34:00Z
Uralbash
<div class="section" id="python-django-pyramid">
<div class="section" id="python">
<h2>Python</h2>
<img alt="_static/2013/200px-Monty_Python's_Flying_Circus.jpg" class="align-left" src="_static/2013/200px-Monty_Python's_Flying_Circus.jpg" />
<p>Название языка произошло вовсе не от вида пресмыкающихся. Автор назвал язык в
честь популярного британского комедийного телешоу 70x «<a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%9B%D0%B5%D1%82%D0%B0%D1%8E%D1%89%D0%B8%D0%B9_%D1%86%D0%B8%D1%80%D0%BA_%D0%9C%D0%BE%D0%BD%D1%82%D0%B8_%D0%9F%D0%B0%D0%B9%D1%82%D0%BE%D0%BD%D0%B0">Летающий цирк Монти
Пайтона</a>».
Но потом все стали его ассоциировать со змеей, ибо змея она и в
африке змея.</p>
<br clear="both"/></div>
<div class="section" id="django">
<h2>Django</h2>
<img alt="_static/2013/220px-Django_Reinhardt_(Gottlieb_07301).jpg" class="align-left" src="_static/2013/220px-Django_Reinhardt_(Gottlieb_07301).jpg" />
<p><a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B9%D0%BD%D1%85%D0%B0%D1%80%D0%B4%D1%82,_%D0%96%D0%B0%D0%BD_%D0%91%D0%B0%D1%82%D0%B8%D1%81%D1%82">Джанго Рейнхардт</a>
— музыкант, в честь которого получил название фреймворк</p>
<br clear="both"/></div>
<div class="section" id="pyramid">
<h2>Pyramid</h2>
<img alt="_static/2013/venus-shpinx-pyramid-vegas2.jpg" class="align-left" src="_static/2013/venus-shpinx-pyramid-vegas2.jpg" style="width: 300px;" />
<p><a class="reference external" href="https://github.com/stevepiercy">stevepiercy</a> ответил так :)</p>
<div class="line-block">
<div class="line"><a class="reference external" href="https://github.com/stevepiercy">stevepiercy</a>: because we have pointy heads</div>
<div class="line"><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></code></div>
</div>
<p><a class="reference external" href="https://github.com/stevepiercy">stevepiercy</a>: but seriously, the decision to merge web app frameworks
into one was made at the Luxor in Las Vegas, which is a hotel shaped like a
pyramid, and the name starts with “Py”, so....</p>
<p>Но если серьезно, то решение об объединении фреймворков в один, было принято
в отеле Luxor в Лас-Вегасе, который имеет форму пирамиды и название начинается
с “Py”...</p>
<br clear="both"/></div>
</div>
Redactor-js WYSIWYG редактор и python
http://uralbash.ru/articles/2012/redactor-js/
2012-11-02T16:11:00Z
2012-11-02T16:11:00Z
Uralbash
<div class="section" id="redactor-js-wysiwyg-python">
<p><a class="reference external" href="https://github.com/dybskiy/redactor-js">Redactor-js</a> - это простой вайсвиг с
возможностью загрузки изображений.</p>
<img alt="_static/2012/redactor-js.png" class="align-center" src="_static/2012/redactor-js.png" />
<div class="line-block">
<div class="line">demo: <a class="reference external" href="http://imperavi.com/redactor/">http://imperavi.com/redactor/</a></div>
<div class="line">github: <a class="reference external" href="https://github.com/dybskiy/redactor-js">https://github.com/dybskiy/redactor-js</a></div>
</div>
<p>Как сочленить это с <a class="reference external" href="http://php.net/">php</a> можно прочитать из документации
<a class="reference external" href="http://imperavi.com/redactor/docs/images/">http://imperavi.com/redactor/docs/images/</a>. Там же есть ссылка на <a class="reference external" href="http://paltman.com/2012/08/15/how-to-setup-upload-handler-for-redactor/">пример с
Django от Patrick Altman</a>. Я
же постараюсь описать как загружать картинки при помощи <a class="reference external" href="http://pylonsproject.org/">pyramid</a> фреймворка,
думаю переписать на что то другое не составит труда.</p>
<p>js функция redactor’а у меня выглядит вот так:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="c"><!-- Redactor is here --></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"/static/redactor/redactor/redactor.css"</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"/static/redactor/redactor/redactor.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></span>
<span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span>
<span class="kd">function</span><span class="p">()</span>
<span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="s1">'#redactor_content'</span><span class="p">).</span><span class="nx">redactor</span><span class="p">({</span>
<span class="nx">imageUpload</span><span class="o">:</span> <span class="s1">'/image/upload'</span><span class="p">,</span>
<span class="nx">imageGetJson</span><span class="o">:</span> <span class="s1">'/image/GetJson'</span><span class="p">,</span>
<span class="nx">mobile</span><span class="o">:</span> <span class="kc">true</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">);</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>вьюха для загрузки изображений:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s1">'upload_image'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">upload_image</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="c1"># путь к директории куда загружать картинку</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'redactor_images'</span><span class="p">)</span>
<span class="n">filename</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span> <span class="o">+</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span><span class="o">.</span><span class="n">filename</span>
<span class="n">input_file</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span><span class="o">.</span><span class="n">file</span>
<span class="c1"># Using the filename like this without cleaning it is very</span>
<span class="c1"># insecure so please keep that in mind when writing your own</span>
<span class="c1"># file handling.</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">output_file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span>
<span class="c1"># Finally write the data to the output file</span>
<span class="n">input_file</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">input_file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">2</span> <span class="o"><<</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span>
<span class="k">break</span>
<span class="n">output_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">output_file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"filelink"</span><span class="p">:</span> <span class="s2">"/static/uploaded/images/"</span> <span class="o">+</span> <span class="n">filename</span><span class="p">}</span>
</pre></div>
</div>
<p>И вьюха для выбора изображений из уже загруженных:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s1">'GetJson'</span><span class="p">),</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">imageGetJson</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'redactor_images'</span><span class="p">)</span>
<span class="n">types</span> <span class="o">=</span> <span class="p">(</span><span class="s1">'*.jpg'</span><span class="p">,</span> <span class="s1">'*.jpeg'</span><span class="p">,</span> <span class="s1">'*.gif'</span><span class="p">)</span> <span class="c1"># the tuple of file types</span>
<span class="n">files_grabbed</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">types</span><span class="p">:</span>
<span class="n">files_grabbed</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="n">path</span> <span class="o">+</span> <span class="s2">"/"</span> <span class="o">+</span> <span class="n">files</span><span class="p">))</span>
<span class="n">images</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="nb">file</span> <span class="ow">in</span> <span class="n">files_grabbed</span><span class="p">:</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
<span class="n">images</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">"thumb"</span><span class="p">:</span> <span class="s2">"/static/uploaded/images/"</span> <span class="o">+</span> <span class="nb">file</span><span class="p">,</span>
<span class="s2">"image"</span><span class="p">:</span> <span class="s2">"/static/uploaded/images/"</span> <span class="o">+</span> <span class="nb">file</span><span class="p">,</span>
<span class="s2">"title"</span><span class="p">:</span> <span class="nb">file</span><span class="p">,</span> <span class="s2">"folder"</span><span class="p">:</span> <span class="s2">"images"</span><span class="p">})</span>
<span class="k">return</span> <span class="n">images</span>
</pre></div>
</div>
<p>Пользуйтесь, хороший редактор.</p>
</div>
Структура Pyramid приложений как в Django
http://uralbash.ru/articles/2012/pyramid_as_django/
2012-07-05T10:42:00Z
2012-07-05T10:42:00Z
Uralbash
<div class="section" id="pyramid-django">
<p>Одной из причин отказа развивать ветку <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> стала его архитектура
проекта. Все контроллеры хранятся в директории <code class="docutils literal"><span class="pre">controllers</span></code>, модели в
<code class="docutils literal"><span class="pre">models</span></code>, шаблоны в <code class="docutils literal"><span class="pre">templates</span></code>. Это очень удобно когда у вас маленький
проект, но если он разрастается до десятков и сотен сущностей, то становится
крайне сложно скакать по этим папкам выискивая нужный файл, относящийся именно
к этой сущности. В <a class="reference external" href="https://www.djangoproject.com/">Django</a> сделано по другому, в проекте хранятся
приложения (<code class="docutils literal"><span class="pre">application</span></code>) - это такие маленькие подпрограммы которые
отвечают за конкретный функционал проекта (например фотогалерея
<a class="reference external" href="https://pypi.python.org/pypi/django-photologue">django-photologue</a> или дерево сайта <a class="reference external" href="https://pypi.python.org/pypi/django-sitetree">django-sitetree</a> и прочее).
Каждое такое приложение имеет свою папку и уже в ней хранятся контроллеры
(<code class="docutils literal"><span class="pre">views</span></code> в данном случае) и модели (<code class="docutils literal"><span class="pre">models</span></code>). Т.е. вместо такой
архитектуры <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Project/
controllers/
controllers1.py
controllers2.py
model/
models1.py
models2.py
templates/
templates1/
templates2/
routes.py
</pre></div>
</div>
<p>мы получаем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Project/
app1/
models.py
routes.py
views.py
app2/
models.py
routes.py
views.py
templates/
templates1/
templates2/
</pre></div>
</div>
<p>Разработчики не стали менять архитектуру <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> и создавать Pylons 2.0, а
начали развивать новый проект <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> с похожей на <a class="reference external" href="https://www.djangoproject.com/">Django</a> структурой
проекта. При этом <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> не считается устаревшим, а просто имеет немного
другой подход к разработке.</p>
<p>Стоит ли сейчас выбирать <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>? Да, если вы его хорошо знаете и не
планируете создавать слишком масштабное приложение, иначе лучше все таки
выбрать <a class="reference external" href="http://pylonsproject.org/">Pyramid</a>.</p>
<p>Посмотрим как в нем организовать структуру проекта:</p>
<p>После создания проект выглядит так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>MyProject/
├── CHANGES.txt
├── development.ini
├── MANIFEST.in
├── myproject
│ ├── __init__.py
│ ├── models.py
│ ├── scripts/
│ ├── static/
│ ├── templates/
│ ├── tests.py
│ └── views.py
├── production.ini
├── README.txt
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>Наша задача перенести <code class="docutils literal"><span class="pre">models.py</span></code>, <code class="docutils literal"><span class="pre">views.py</span></code>, <code class="docutils literal"><span class="pre">tests.py</span></code> в <code class="docutils literal"><span class="pre">app1</span></code>.
Создаем папку <code class="docutils literal"><span class="pre">app1</span></code> и переносим файлы.</p>
<p>Должно получится так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>MyProject/
.
├── CHANGES.txt
├── development.ini
├── MANIFEST.in
├── myproject
│ ├── app1
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ ├── scripts
│ │ ├── initializedb.py
│ │ └── __init__.py
│ ├── static
│ │ ├── favicon.ico
│ │ ├── footerbg.png
│ │ ├── headerbg.png
│ │ ├── ie6.css
│ │ ├── middlebg.png
│ │ ├── pylons.css
│ │ ├── pyramid.png
│ │ ├── pyramid-small.png
│ │ └── transparent.gif
│ └── templates
│ └── mytemplate.pt
├── production.ini
├── README.txt
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">__init__.py</span></code> в проекте:</p>
<p>Вместо</p>
<div class="highlight-python"><div class="highlight"><pre><span></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">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
<span class="sd">""" This function returns a Pyramid WSGI application.</span>
<span class="sd"> """</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</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">settings</span><span class="o">=</span><span class="n">settings</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_static_view</span><span class="p">(</span><span class="s1">'static'</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">,</span> <span class="n">cache_max_age</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'home'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
<span class="k">return</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
</pre></div>
</div>
<p>Делаем</p>
<div class="highlight-python"><div class="highlight"><pre><span></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">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
<span class="sd">""" This function returns a Pyramid WSGI application.</span>
<span class="sd"> """</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</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">settings</span><span class="o">=</span><span class="n">settings</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_static_view</span><span class="p">(</span><span class="s1">'static'</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">,</span> <span class="n">cache_max_age</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="c1"># add config for each of your subapps</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'myproject.app1'</span><span class="p">)</span>
<span class="c1"># pyramid_jinja2 configuration</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'pyramid_jinja2'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_jinja2_search_path</span><span class="p">(</span><span class="s2">"myproject:templates"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
</pre></div>
</div>
<p>Теперь в этом <code class="docutils literal"><span class="pre">__init__.py</span></code> мы будем хранить глобальные настройки, а в инитах
апликайшинах настройки самих апликайшинов.</p>
<p>Добавляем <code class="docutils literal"><span class="pre">models.py</span></code> в основной проект:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>MyProject/
.
├── CHANGES.txt
├── development.ini
├── MANIFEST.in
├── myproject
│ ├── app1
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ ├── scripts
│ │ ├── initializedb.py
│ │ └── __init__.py
│ ├── models.py
│ ├── static
│ │ ├── favicon.ico
│ │ ├── footerbg.png
│ │ ├── headerbg.png
│ │ ├── ie6.css
│ │ ├── middlebg.png
│ │ ├── pylons.css
│ │ ├── pyramid.png
│ │ ├── pyramid-small.png
│ │ └── transparent.gif
│ └── templates
│ └── mytemplate.pt
├── production.ini
├── README.txt
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>В нем будет хранится сессия <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> общая для всех проектов:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">zope.sqlalchemy</span> <span class="kn">import</span> <span class="n">ZopeTransactionExtension</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">scoped_session</span><span class="p">,</span>
<span class="n">sessionmaker</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">DBSession</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">extension</span><span class="o">=</span><span class="n">ZopeTransactionExtension</span><span class="p">()))</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">__init__.py</span></code> в <code class="docutils literal"><span class="pre">app1</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">includeme</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'home'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">models.py</span></code> в <code class="docutils literal"><span class="pre">app1</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Column</span><span class="p">,</span>
<span class="n">Integer</span><span class="p">,</span>
<span class="n">Text</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">scoped_session</span><span class="p">,</span>
<span class="n">sessionmaker</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">DBSession</span><span class="p">,</span>
<span class="n">Base</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">class</span> <span class="nc">MyModel</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'models'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Text</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__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="n">value</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>
<span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">tests.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unittest</span>
<span class="kn">import</span> <span class="nn">transaction</span>
<span class="kn">from</span> <span class="nn">pyramid</span> <span class="kn">import</span> <span class="n">testing</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">class</span> <span class="nc">TestMyView</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="n">testing</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite://'</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Base</span><span class="p">,</span>
<span class="n">MyModel</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="k">with</span> <span class="n">transaction</span><span class="o">.</span><span class="n">manager</span><span class="p">:</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">MyModel</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'one'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">55</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
<span class="n">testing</span><span class="o">.</span><span class="n">tearDown</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">test_it</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="kn">from</span> <span class="nn">.views</span> <span class="kn">import</span> <span class="n">my_view</span>
<span class="n">request</span> <span class="o">=</span> <span class="n">testing</span><span class="o">.</span><span class="n">DummyRequest</span><span class="p">()</span>
<span class="n">info</span> <span class="o">=</span> <span class="n">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">info</span><span class="p">[</span><span class="s1">'one'</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">'one'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">info</span><span class="p">[</span><span class="s1">'project'</span><span class="p">],</span> <span class="s1">'MyProject'</span><span class="p">)</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">views.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy.exc</span> <span class="kn">import</span> <span class="n">DBAPIError</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">MyModel</span>
<span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s1">'home'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'../templates/mytemplate.pt'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">one</span> <span class="o">=</span> <span class="n">DBSession</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">MyModel</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">MyModel</span><span class="o">.</span><span class="n">name</span><span class="o">==</span><span class="s1">'one'</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="k">except</span> <span class="n">DBAPIError</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">conn_err_msg</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="s1">'text/plain'</span><span class="p">,</span> <span class="n">status_int</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'one'</span><span class="p">:</span><span class="n">one</span><span class="p">,</span> <span class="s1">'project'</span><span class="p">:</span><span class="s1">'MyProject'</span><span class="p">}</span>
<span class="n">conn_err_msg</span> <span class="o">=</span> <span class="s2">"""</span><span class="se">\</span>
<span class="s2">Pyramid is having a problem using your SQL database. The problem</span>
<span class="s2">might be caused by one of the following things:</span>
<span class="s2">A. You may need to run the "initialize_MyProject_db" script</span>
<span class="s2"> to initialize your database tables. Check your virtual</span>
<span class="s2"> environment's "bin" directory for this script and try to run it.</span>
<span class="s2">B. Your database server may not be running. Check that the</span>
<span class="s2"> database server referred to by the "sqlalchemy.url" setting in</span>
<span class="s2"> your "development.ini" file is running.</span>
<span class="s2">After you fix the problem, please restart the Pyramid application to</span>
<span class="s2">try it again.</span>
<span class="s2">"""</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">initializedb.py</span></code> в <code class="docutils literal"><span class="pre">scripts</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">transaction</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">pyramid.paster</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">get_appsettings</span><span class="p">,</span>
<span class="n">setup_logging</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">DBSession</span><span class="p">,</span>
<span class="n">Base</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..app1.models</span> <span class="kn">import</span> <span class="n">MyModel</span>
<span class="k">def</span> <span class="nf">usage</span><span class="p">(</span><span class="n">argv</span><span class="p">):</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="s1">'usage: </span><span class="si">%s</span><span class="s1"> <config_uri></span><span class="se">\n</span><span class="s1">'</span>
<span class="s1">'(example: "</span><span class="si">%s</span><span class="s1"> development.ini")'</span> <span class="o">%</span> <span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">cmd</span><span class="p">))</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">argv</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">argv</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">usage</span><span class="p">(</span><span class="n">argv</span><span class="p">)</span>
<span class="n">config_uri</span> <span class="o">=</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">setup_logging</span><span class="p">(</span><span class="n">config_uri</span><span class="p">)</span>
<span class="n">settings</span> <span class="o">=</span> <span class="n">get_appsettings</span><span class="p">(</span><span class="n">config_uri</span><span class="p">)</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="k">with</span> <span class="n">transaction</span><span class="o">.</span><span class="n">manager</span><span class="p">:</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">MyModel</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'one'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
</pre></div>
</div>
<div class="line-block">
<div class="line">Выполняем <code class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">install</span></code>, запускаем проект, профит!</div>
<div class="line">Остальные апликайшины добавляются по аналогии.</div>
<div class="line">Навеянно этим <a class="reference external" href="http://stackoverflow.com/questions/6012991/pyramid-project-structure">http://stackoverflow.com/questions/6012991/pyramid-project-structure</a></div>
</div>
</div>
Pylons + SQLalchemy расширенная модель (Mixin)
http://uralbash.ru/articles/2011/sqlalchemy_mixin/
2011-10-27T00:07:00Z
2011-10-27T00:07:00Z
Uralbash
<div class="section" id="pylons-sqlalchemy-mixin">
<p>Часто при проектировании структуры БД появляется необходимость повторять одни
и те же действия с таблицами. Добавлять одинаковые поля, ссылки, счетчики и
т.д. Модели в <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> (<a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a>), как и в большинстве других фреймворках
использующих паттерн MVC, являются классом и соответственно могут быть
унаследованы от других классов. Это позволяет нам избежать рутинной работы с
повторяющимися действиями.</p>
<p>Все расширения для наших моделей будем добавлять в <code class="docutils literal"><span class="pre">models/common.py</span></code>.
Создадим базовую модель в которой будет поле <code class="docutils literal"><span class="pre">id</span></code>, автоматическая генерация
названия таблицы (<code class="docutils literal"><span class="pre">__tablename__</span></code>) и метод выбора элемента по <code class="docutils literal"><span class="pre">id</span></code> (<code class="docutils literal"><span class="pre">SELECT</span> <span class="pre">*</span> <span class="pre">FROM</span>
<span class="pre">table</span> <span class="pre">WHERE</span> <span class="pre">id=integer</span></code>):</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Базовая модель. Добавляет во всех наследников поле id и атрибут</span>
<span class="sd"> __tablename__ который заполняется автоматически. Имя таблицы берется из</span>
<span class="sd"> названия класса и переводится в нижний регистр. Таблица наследник имеет по</span>
<span class="sd"> умолчанию название и поле id, сильно облегчая жизнь.</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">__tablename__</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="n">has_inherited_table</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="ow">and</span>
<span class="n">Tablename</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__bases__</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="c1"># Method "byId" for use in code like this:</span>
<span class="c1"># session.query(Table).byId(5)</span>
<span class="c1">#</span>
<span class="c1"># SQL statement like:</span>
<span class="c1"># SELECT * FROM Table WHERE id = 5;</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">byId</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span> <span class="p">:</span>
<span class="k">return</span> <span class="n">Session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="nb">id</span> <span class="o">=</span> <span class="nb">id</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">autoincrement</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
</div>
<p>Метод <code class="docutils literal"><span class="pre">byId</span></code> сильно сокращает запись в коде например:</p>
<div class="line-block">
<div class="line">before: <code class="docutils literal"><span class="pre">Session.query(net).filter_by(id</span> <span class="pre">=</span> <span class="pre">id).first()</span></code></div>
<div class="line">after: <code class="docutils literal"><span class="pre">net.byId(id)</span></code></div>
</div>
<p>Теперь создадим нашу модель унаследовав все плюшки с базовой модели:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Net</span><span class="p">(</span><span class="n">Base</span><span class="p">,</span> <span class="n">DeclarativeBase</span><span class="p">):</span>
<span class="sd">"""Net or subnet."""</span>
<span class="n">cidr</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">postgresql</span><span class="o">.</span><span class="n">CIDR</span><span class="p">,</span> <span class="n">index</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">UnicodeText</span><span class="p">())</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cidr</span><span class="o">=</span><span class="s1">''</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cidr</span> <span class="o">=</span> <span class="n">cidr</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">cidr</span>
</pre></div>
</div>
<p>Наша модель связанна с БД при помощи наследования от <code class="docutils literal"><span class="pre">DeclarativeBase</span></code>, имеет
название, поле <code class="docutils literal"><span class="pre">id</span></code> и метод <code class="docutils literal"><span class="pre">byId</span></code> благодаря наследованию от базовой модели
<code class="docutils literal"><span class="pre">Base</span></code> из файла <code class="docutils literal"><span class="pre">common.py</span></code>.</p>
<p>Для более наглядного примера создадим типовую модель для таблиц которые должны
содержать служебную информацию. Модель будет добавлять в другие модели поля:</p>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">created_by</span></code> - кто создал</div>
<div class="line"><code class="docutils literal"><span class="pre">updated_by</span></code> - последний кто обновил</div>
<div class="line"><code class="docutils literal"><span class="pre">created_at</span></code> - дата создания</div>
<div class="line"><code class="docutils literal"><span class="pre">updated_at</span></code> - дата последнего обновления</div>
</div>
<p>Поля заполняются автоматически. Кто создал и обновил ссылаются на модель
<code class="docutils literal"><span class="pre">auth.User</span></code>. Пользователь берется из текущей сессии, при помощи библиотеки
<code class="docutils literal"><span class="pre">lib.auth</span></code> и метода <code class="docutils literal"><span class="pre">get_user</span></code>. Откуда взялась модель <code class="docutils literal"><span class="pre">User</span></code> можно узнать из этой
статьи <a class="reference internal" href="../../../articles/2011/repoze.what/#repoze-what"><span class="std std-ref">Авторизация в Pylons за 5 мин при помощи repoze.what</span></a>.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CreatedMixin</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Абстрактная примесь которая добавляет в другие модели поля:</span>
<span class="sd"> created_by - кто создал</span>
<span class="sd"> updated_by - последний кто обновил</span>
<span class="sd"> created_at - дата создания</span>
<span class="sd"> updated_at - дата последнего обновления</span>
<span class="sd"> Поля заполняются автоматически. Кто создал и обновил ссылаются на модель</span>
<span class="sd"> auth.User. Пользователь берется из текущей сессии, при помощи библиотеки</span>
<span class="sd"> lib.auth и метода get_user</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">created_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">updated_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="n">created_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
<span class="n">updated_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
<span class="n">onupdate</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
</pre></div>
</div>
<p>Внешние ссылки и другие атрибуты отличающиеся от обычных полей нужно добавлять
при помощи декоратора <code class="docutils literal"><span class="pre">declare_attr</span></code>. Теперь меняем нашу модель <code class="docutils literal"><span class="pre">Net</span></code> просто
добавив <code class="docutils literal"><span class="pre">CreateMixin</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Net</span><span class="p">(</span><span class="n">Base</span><span class="p">,</span> <span class="n">DeclarativeBase</span><span class="p">,</span> <span class="n">CreatedMixin</span><span class="p">):</span>
</pre></div>
</div>
<p>Вот полный листинг <code class="docutils literal"><span class="pre">common.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># coding=utf-8</span>
<span class="sd">"""Модуль с типовыми моделями</span>
<span class="sd">"""</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">ForeignKey</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">relation</span><span class="p">,</span> <span class="n">relationship</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.types</span> <span class="kn">import</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span><span class="p">,</span> <span class="n">DateTime</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declared_attr</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">has_inherited_table</span>
<span class="kn">from</span> <span class="nn">gottlieb.model.auth</span> <span class="kn">import</span> <span class="n">User</span>
<span class="kn">from</span> <span class="nn">gottlieb.lib</span> <span class="kn">import</span> <span class="n">auth</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span> <span class="k">as</span> <span class="n">dt</span>
<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Базовая модель. Добавляет во всех наследников поле id и атрибут</span>
<span class="sd"> __tablename__ который заполняется автоматически. Имя таблицы берется из</span>
<span class="sd"> названия класса и переводится в нижний регистр. Таблица наследник имеет по</span>
<span class="sd"> умолчанию название и поле id, сильно облегчая жизнь.</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">__tablename__</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="n">has_inherited_table</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="ow">and</span>
<span class="n">Tablename</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__bases__</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="c1"># Method "byId" for use in code like this:</span>
<span class="c1"># session.query(Table).byId(5)</span>
<span class="c1">#</span>
<span class="c1"># SQL statement like:</span>
<span class="c1"># SELECT * FROM Table WHERE id = 5;</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">byId</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span> <span class="p">:</span>
<span class="k">return</span> <span class="n">Session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="nb">id</span> <span class="o">=</span> <span class="nb">id</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">autoincrement</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">CreatedMixin</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Абстрактная примесь которая добавляет в другие модели поля:</span>
<span class="sd"> created_by - кто создал</span>
<span class="sd"> updated_by - последний кто обновил</span>
<span class="sd"> created_at - дата создания</span>
<span class="sd"> updated_at - дата последнего обновления</span>
<span class="sd"> Поля заполняются автоматически. Кто создал и обновил ссылаются на модель</span>
<span class="sd"> auth.User. Пользователь берется из текущей сессии, при помощи библиотеки</span>
<span class="sd"> lib.auth и метода get_user</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">created_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">updated_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="n">created_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
<span class="n">updated_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
<span class="n">onupdate</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
</pre></div>
</div>
<p>Для полной картины приведу аналогичный пример на <a class="reference external" href="https://www.djangoproject.com/">Django</a> + DjangoORM.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">myapp/accompaniment/models.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>
<span class="c1"># Create your models here.</span>
<span class="k">class</span> <span class="nc">ExtendedModel</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">created_by</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s1">'</span><span class="si">%(class)s</span><span class="s1">_creator'</span><span class="p">)</span>
<span class="n">created_time</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">auto_now_add</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">modified_by</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s1">'</span><span class="si">%(class)s</span><span class="s1">_modifier'</span><span class="p">)</span>
<span class="n">modified_time</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">auto_now</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">abstract</span> <span class="o">=</span> <span class="bp">True</span>
</pre></div>
</div>
</div>
<p>В папке accompaniment я привык держать всякие такие хелперы для проекта. Теперь
используем эту модель в нашем проекте <code class="docutils literal"><span class="pre">myapp/projectname/models.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">accompaniment.models</span> <span class="kn">import</span> <span class="n">ExtendedModel</span>
<span class="k">class</span> <span class="nc">Ticket</span><span class="p">(</span><span class="n">ExtendedModel</span><span class="p">):</span>
<span class="n">OPEN_STATUS</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">REOPENED_STATUS</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">RESOLVED_STATUS</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">CLOSED_STATUS</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">DUPLICATE_STATUS</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">STATUS_CHOICES</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="n">OPEN_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Open'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">REOPENED_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Reopened'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">RESOLVED_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Resolved'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">CLOSED_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Closed'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">DUPLICATE_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Duplicate'</span><span class="p">)),</span>
<span class="p">)</span>
<span class="n">PRIORITY_CHOICES</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'1. Critical'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'2. High'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'3. Normal'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'4. Low'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'5. Very Low'</span><span class="p">)),</span>
<span class="p">)</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Title'</span><span class="p">),</span>
<span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">queue</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span>
<span class="n">Queue</span><span class="p">,</span>
<span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s1">'Queue'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">assigned_to</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span>
<span class="n">User</span><span class="p">,</span>
<span class="n">related_name</span><span class="o">=</span><span class="s1">'assigned_to'</span><span class="p">,</span>
<span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s1">'Assigned to'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">status</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Status'</span><span class="p">),</span>
<span class="n">choices</span><span class="o">=</span><span class="n">STATUS_CHOICES</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="n">OPEN_STATUS</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Description'</span><span class="p">),</span>
<span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">help_text</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s1">'The content of the customers query.'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">priority</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Priority'</span><span class="p">),</span>
<span class="n">choices</span><span class="o">=</span><span class="n">PRIORITY_CHOICES</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
<span class="n">blank</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">get_latest_by</span> <span class="o">=</span> <span class="s2">"created"</span>
<span class="n">verbose_name</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Заявки'</span>
<span class="n">verbose_name_plural</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Заявки'</span>
<span class="k">def</span> <span class="fm">__unicode__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">u</span><span class="s1">'</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
<span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">force_insert</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">force_update</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">priority</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">priority</span> <span class="o">=</span> <span class="mi">3</span>
<span class="nb">super</span><span class="p">(</span><span class="n">Ticket</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">force_insert</span><span class="p">,</span> <span class="n">force_update</span><span class="p">)</span>
</pre></div>
</div>
<p>Такой несложный метод освобождает нас от размножения кучи одинаковых полей в
моделях.</p>
<p>Update: в моделях Mixin был атрибут <code class="docutils literal"><span class="pre">__abstract__</span> <span class="pre">=</span> <span class="pre">True</span></code> это неправильно,
так-как все таблицы стают абстрактными. НО! Это вполне прокатит на версиях
меньше 0.7, там этот атрибут почему-то не учитывается. На 0.7 версии работает
как надо. Вот описание проблемы: <a class="reference external" href="http://stackoverflow.com/questions/7990790/sqlalchemy-0-7-mapperevent-error">stackoverflow</a></p>
</div>
SQLalchemy UML диаграмма
http://uralbash.ru/articles/2011/sqlalchemy_uml/
2011-10-24T19:27:00Z
2011-10-24T19:27:00Z
Uralbash
<div class="section" id="sqlalchemy-uml">
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">UPD: <a class="reference external" href="https://pypi.python.org/pypi/sadisplay">sadisplay</a> - замечательная штука!</p>
</div>
<p>Для визуализации своей базы в <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> удобно использовать <a class="reference external" href="http://www.graphviz.org/">graphviz</a>
и библиотеку <a class="reference external" href="https://github.com/fschulze/sqlalchemy_schemadisplay">sqlalchemy_schemadisplay</a>.</p>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-get install graphviz
$ pip install sqlalchemy_schemadisplay
</pre></div>
</div>
<p>Далее читаем доки <a class="reference external" href="http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SchemaDisplay">SQLAlchemy Schema Display</a></p>
<p>Для Ъ:</p>
<p>Схема БД строится на основании данных базы.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">MetaData</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_schemadisplay</span> <span class="kn">import</span> <span class="n">create_schema_graph</span>
<span class="c1"># create the pydot graph object by autoloading all tables via a bound metadata object</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">create_schema_graph</span><span class="p">(</span>
<span class="n">metadata</span><span class="o">=</span><span class="n">MetaData</span><span class="p">(</span><span class="s1">'postgres://user:pwd@host/database'</span><span class="p">),</span>
<span class="n">show_datatypes</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="c1"># The image would get nasty big if we'd show the datatypes</span>
<span class="n">show_indexes</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="c1"># ditto for indexes</span>
<span class="n">rankdir</span><span class="o">=</span><span class="s1">'LR'</span><span class="p">,</span> <span class="c1"># From left to right (instead of top to bottom)</span>
<span class="n">concentrate</span><span class="o">=</span><span class="bp">False</span> <span class="c1"># Don't try to join the relation lines together</span>
<span class="p">)</span>
<span class="n">graph</span><span class="o">.</span><span class="n">write_png</span><span class="p">(</span><span class="s1">'dbschema.png'</span><span class="p">)</span> <span class="c1"># write out the file</span>
</pre></div>
</div>
<div class="figure align-center" id="id1">
<img alt="_static/2011/dbschema.png" src="_static/2011/dbschema.png" />
<p class="caption"><span class="caption-text">Схема БД Postgres</span></p>
</div>
<p>Схема UML строится по моделям проекта.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">myapp</span> <span class="kn">import</span> <span class="n">model</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_schemadisplay</span> <span class="kn">import</span> <span class="n">create_uml_graph</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">class_mapper</span>
<span class="c1"># lets find all the mappers in our model</span>
<span class="n">mappers</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">attr</span> <span class="ow">in</span> <span class="nb">dir</span><span class="p">(</span><span class="n">model</span><span class="p">):</span>
<span class="k">if</span> <span class="n">attr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'_'</span><span class="p">:</span> <span class="k">continue</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">cls</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
<span class="n">mappers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">class_mapper</span><span class="p">(</span><span class="bp">cls</span><span class="p">))</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
<span class="c1"># pass them to the function and set some formatting options</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">create_uml_graph</span><span class="p">(</span><span class="n">mappers</span><span class="p">,</span>
<span class="n">show_operations</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="c1"># not necessary in this case</span>
<span class="n">show_multiplicity_one</span><span class="o">=</span><span class="bp">False</span> <span class="c1"># some people like to see the ones, some don't</span>
<span class="p">)</span>
<span class="n">graph</span><span class="o">.</span><span class="n">write_png</span><span class="p">(</span><span class="s1">'schema.png'</span><span class="p">)</span> <span class="c1"># write out the file</span>
</pre></div>
</div>
<div class="figure align-center" id="id2">
<img alt="_static/2011/schema.png" src="_static/2011/schema.png" />
<p class="caption"><span class="caption-text">Схема моделей в Pylons</span></p>
</div>
<p>Для <a class="reference external" href="https://www.djangoproject.com/">Django</a> кодеров есть модуль <a class="reference external" href="https://github.com/django-extensions/django-extensions">django-extension</a> который добавляет
много полезных команд для <code class="docutils literal"><span class="pre">manage.py</span></code>. Вот мой вариант скрипта для <a class="reference external" href="https://www.djangoproject.com/">Django</a>:</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">project_dir/_visualozation/visualized.sh</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">curent_d</span><span class="o">=</span><span class="s2">"`date +%H%M_%d%m%y`"</span>
<span class="nb">exec</span> python ../manage.py graph_models -a -g -o scheme_of_<span class="nv">$curent_d</span>.png
</pre></div>
</div>
</div>
<div class="figure align-center" id="id4">
<img alt="_static/2011/django_uml.png" src="_static/2011/django_uml.png" />
<p class="caption"><span class="caption-text">пример django-extension + graphviz</span></p>
</div>
</div>