<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0cFSHo6eSp7ImA9WhRQF00.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130</id><updated>2011-12-12T20:56:59.411+04:00</updated><category term="math" /><category term="генератор отчетов" /><category term="SQL" /><category term="refactoring" /><category term="must have" /><category term="PyQt" /><category term="unittest" /><category term="PyWin32" /><category term="кронтаб" /><category term="воспроизведение" /><category term="report generator" /><category term="sqlite" /><category term="repgen" /><category term="model-view" /><category term="внешний ключ" /><category term="PyNCReport" /><category term="модель-представление" /><category term="Phonon" /><category term="тестирование" /><category term="аудио" /><category term="метаданные" /><category term="крон" /><category term="GUI" /><category term="маппинг виджетов" /><category term="ui" /><category term="audio" /><category term="инструмент" /><category term="sceduler" /><category term="python" /><category term="интерфейс" /><category term="диалог" /><category term="MDI" /><category term="отчеты" /><category term="Qt" /><category term="сборка" /><category term="automation" /><category term="cron" /><category term="recipes" /><category term="планировщик" /><category term="звук" /><category term="crontab" /><category term="рецепты" /><category term="виртуализация" /><category term="NCReport" /><category term="дублирование кода" /><category term="модели Qt" /><title>class QSqliteBlog(QObject):</title><subtitle type="html">Блог в первую очередь для себя, для сохранения сакральных знаний о питоновских и иже с ними граблях, плюшках и т.п. Хотя, если еще кому-то окажется полезным, буду только рад.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://pythonistaa.blogspot.com/" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>18</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ClassQsqliteblogqobject" /><feedburner:info uri="classqsqliteblogqobject" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>ClassQsqliteblogqobject</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry gd:etag="W/&quot;C0IFQ3o7fip7ImA9WhRRF0k.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-1319172532298750584</id><published>2011-12-01T13:39:00.001+04:00</published><updated>2011-12-01T16:11:52.406+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-01T16:11:52.406+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="кронтаб" /><category scheme="http://www.blogger.com/atom/ns#" term="крон" /><category scheme="http://www.blogger.com/atom/ns#" term="планировщик" /><category scheme="http://www.blogger.com/atom/ns#" term="sceduler" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="must have" /><category scheme="http://www.blogger.com/atom/ns#" term="cron" /><category scheme="http://www.blogger.com/atom/ns#" term="crontab" /><title>Парсим выражение crontab</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/1319172532298750584/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/12/crontab.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/1319172532298750584?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/1319172532298750584?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/ffBbNUOB-uk/crontab.html" title="Парсим выражение crontab" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Crontab - формат файла заданий для планировщика cron. Знаменит простотой, гибкостью и мощью, позволяющими задать практически любую периодичность для выполнения заданий.

Как только выяснилось, что придется писать свой планировщик, мой взгляд сразу обратился на crontab. Но, испугавшись кажущейся сложности его парсинга, я начал придумывать другой, возможно более слабый, но простой в реализации, 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EZTn_ySTTH6h8M2Jn4-VUMay6Mc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EZTn_ySTTH6h8M2Jn4-VUMay6Mc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EZTn_ySTTH6h8M2Jn4-VUMay6Mc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EZTn_ySTTH6h8M2Jn4-VUMay6Mc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/ffBbNUOB-uk" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/12/crontab.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YHR3wzfCp7ImA9WhRREE4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-929311035419767307</id><published>2011-11-23T11:37:00.001+04:00</published><updated>2011-11-23T11:58:56.284+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-23T11:58:56.284+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="звук" /><category scheme="http://www.blogger.com/atom/ns#" term="воспроизведение" /><category scheme="http://www.blogger.com/atom/ns#" term="Phonon" /><category scheme="http://www.blogger.com/atom/ns#" term="аудио" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="audio" /><category scheme="http://www.blogger.com/atom/ns#" term="Qt" /><title>Phonon: Я хочу, чтобы песня звучала</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/929311035419767307/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/11/phonon.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/929311035419767307?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/929311035419767307?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/5m0hW2eiF_Q/phonon.html" title="Phonon: Я хочу, чтобы песня звучала" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Опыт показывает: пользователь рабочего места, связанного со специфической периферией (автоматизированная касса, испытательный стенд, терминал сбора данных), всегда хочет звукового уведомления о ключевых событиях и нештатных ситуациях. Не миновала чаша сия и меня.

Задача, в общем, тривиальна: хочется, чтобы в определенные моменты программа издавала определенный звук. Какой именно звук, должно 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/L5pRBfUTCGbnUUwqCL6UlEIxUBQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/L5pRBfUTCGbnUUwqCL6UlEIxUBQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/L5pRBfUTCGbnUUwqCL6UlEIxUBQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/L5pRBfUTCGbnUUwqCL6UlEIxUBQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/5m0hW2eiF_Q" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/11/phonon.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4DQX8zcSp7ImA9WhdaGE8.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-2340463315794296494</id><published>2011-10-28T22:35:00.000+04:00</published><updated>2011-10-28T22:36:10.189+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-28T22:36:10.189+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="рецепты" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="math" /><category scheme="http://www.blogger.com/atom/ns#" term="recipes" /><title>Рецептики: Проверить дробную часть</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/2340463315794296494/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/10/blog-post_3826.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2340463315794296494?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2340463315794296494?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/ynFy-4dGgk0/blog-post_3826.html" title="Рецептики: Проверить дробную часть" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Проверить, имеет ли число ненулевую дробную часть, можно так:

&amp;gt;&amp;gt;&amp;gt; import math
&amp;gt;&amp;gt;&amp;gt; x = 10.0
&amp;gt;&amp;gt;&amp;gt; bool(math.modf(x)[0])
False
&amp;gt;&amp;gt;&amp;gt; x = 10
&amp;gt;&amp;gt;&amp;gt; bool(math.modf(x)[0])
False
&amp;gt;&amp;gt;&amp;gt; x = 10.7
&amp;gt;&amp;gt;&amp;gt; bool(math.modf(x)[0])
True
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9EEBMelqI6K8piOPDZX5RM10QUw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9EEBMelqI6K8piOPDZX5RM10QUw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9EEBMelqI6K8piOPDZX5RM10QUw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9EEBMelqI6K8piOPDZX5RM10QUw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/ynFy-4dGgk0" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/10/blog-post_3826.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIFRH85cSp7ImA9WhdaGE8.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-4831224001330468904</id><published>2011-10-28T19:49:00.000+04:00</published><updated>2011-10-28T22:28:35.129+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-28T22:28:35.129+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="рецепты" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="recipes" /><title>Рецептики: Удалить переводы строки и возвраты каретки</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/4831224001330468904/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/10/blog-post_28.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/4831224001330468904?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/4831224001330468904?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/EXWeAOuUfDM/blog-post_28.html" title="Рецептики: Удалить переводы строки и возвраты каретки" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Решил для разнообразия иногда публиковать мелкие посты с рецептиками.

Удаление из строки переводов строк и возвратов каретки:

&amp;gt;&amp;gt;&amp;gt; s = 'asasd\nasdasd\r\nasdasd\nasdasd'
&amp;gt;&amp;gt;&amp;gt; ''.join(s.splitlines())
'asasdasdasdasdasdasdasd'

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XUArF9NzxKcU2JBBqkB49DVkszQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XUArF9NzxKcU2JBBqkB49DVkszQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XUArF9NzxKcU2JBBqkB49DVkszQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XUArF9NzxKcU2JBBqkB49DVkszQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/EXWeAOuUfDM" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/10/blog-post_28.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEARHk7cSp7ImA9WhdaF0k.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-7319460978845916507</id><published>2011-10-28T00:26:00.002+04:00</published><updated>2011-10-28T00:34:05.709+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-28T00:34:05.709+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="генератор отчетов" /><category scheme="http://www.blogger.com/atom/ns#" term="report generator" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="repgen" /><category scheme="http://www.blogger.com/atom/ns#" term="Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="PyNCReport" /><category scheme="http://www.blogger.com/atom/ns#" term="сборка" /><category scheme="http://www.blogger.com/atom/ns#" term="отчеты" /><category scheme="http://www.blogger.com/atom/ns#" term="NCReport" /><title>PyNCReport: сборка и установка под Windows</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/7319460978845916507/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/10/pyncreport-windows.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7319460978845916507?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7319460978845916507?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/BCXNUVpQUTQ/pyncreport-windows.html" title="PyNCReport: сборка и установка под Windows" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Всякой уважающей себя учетной программе, даже самой маленькой, требуется подсистема отчетов. Ну любят клиенты бумажные отчеты. Времена, когда подсистемы отчетов писали руками и с нуля каждый под себя, слава высшему разуму, давно прошли. Сегодня разработчик ищет подходящий генератор отчета (далее репген) и прикручивает его к своему творению, чем экономит собственное время, деньги работодателя и 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ie11WGFNHFCIYOLAzHAYlKEkhVY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ie11WGFNHFCIYOLAzHAYlKEkhVY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ie11WGFNHFCIYOLAzHAYlKEkhVY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ie11WGFNHFCIYOLAzHAYlKEkhVY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/BCXNUVpQUTQ" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/10/pyncreport-windows.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMGRHc8eSp7ImA9WhdbFU4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-7542944708924122832</id><published>2011-10-14T00:36:00.000+04:00</published><updated>2011-10-14T00:40:25.971+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-14T00:40:25.971+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="модель-представление" /><category scheme="http://www.blogger.com/atom/ns#" term="модели Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="внешний ключ" /><category scheme="http://www.blogger.com/atom/ns#" term="model-view" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Очистка значений внешних ключей в модели</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/7542944708924122832/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/10/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7542944708924122832?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7542944708924122832?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/2vHd04-5jK0/blog-post.html" title="Очистка значений внешних ключей в модели" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">В предыдущем посте я благополучно боролся с отбрасыванием записей, содержащих пустые внешние ключи. Практически сразу возникла в некотором роде обратная задача - уметь очищать поля внешних ключей в модели, как в коде, так и из интерфейса (я встречал мнение, что пустые внешние ключи - грубая ошибка проектирования и этого надо всячески избегать; интересно, в каком мире эти люди живут?). 

Сначала 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/_dTMn8Fex5KECD1k_p88L7giWqU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_dTMn8Fex5KECD1k_p88L7giWqU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/_dTMn8Fex5KECD1k_p88L7giWqU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_dTMn8Fex5KECD1k_p88L7giWqU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/2vHd04-5jK0" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/10/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYNRHY-eCp7ImA9WhdbFU4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-2751280268185620559</id><published>2011-10-07T11:44:00.001+04:00</published><updated>2011-10-14T00:36:35.850+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-14T00:36:35.850+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="модель-представление" /><category scheme="http://www.blogger.com/atom/ns#" term="модели Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="внешний ключ" /><category scheme="http://www.blogger.com/atom/ns#" term="model-view" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="SQL" /><title>Некорректный SQL-запрос SELECT в QSqlRelationalTableModel</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/2751280268185620559/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/10/sql-select-qsqlrelationaltablemodel.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2751280268185620559?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2751280268185620559?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/607HkwazL2s/sql-select-qsqlrelationaltablemodel.html" title="Некорректный SQL-запрос SELECT в QSqlRelationalTableModel" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Было замечено, что в QTableView, настроенном на QRelationalTableModel отображает не все строки таблицы, в частности строки, где значение хотя бы одного поля внешнего ключа (поля, у которых есть QRelation) равно NULL. Более того, оказалось, что эти строки отсутствуют и в модели.

Исследование показало, что QRelationalTableMode.selectStatement возвращает запрос следующего вида: 


SELECT tbl.fld1,

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/QV2I4VgguY2MFXG9EZ_MjGk8NTk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/QV2I4VgguY2MFXG9EZ_MjGk8NTk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/QV2I4VgguY2MFXG9EZ_MjGk8NTk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/QV2I4VgguY2MFXG9EZ_MjGk8NTk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/607HkwazL2s" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/10/sql-select-qsqlrelationaltablemodel.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkECSXsyeip7ImA9WhdUGU0.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-2483752600804749838</id><published>2011-09-28T00:02:00.000+04:00</published><updated>2011-10-06T15:31:08.592+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-06T15:31:08.592+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="MDI" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="GUI" /><category scheme="http://www.blogger.com/atom/ns#" term="интерфейс" /><title>Тюнинг вкладок QMdiArea</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/2483752600804749838/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/09/qmdiarea.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2483752600804749838?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2483752600804749838?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/8_zZebFqqos/qmdiarea.html" title="Тюнинг вкладок QMdiArea" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-OoYj7iU--jI/ToImphR8GuI/AAAAAAAAAFc/FdWBMWUv0eA/s72-c/firsttabs.png" height="72" width="72" /><thr:total>0</thr:total><content type="html">Главное окно проекта должно быть многодокументным и в соответствии с современным стандартом де-факто хочется отображать дочерние окна на отдельных вкладках. Для этого в качестве центрального виджета главного окна нужно использовать QMdiArea и установить режим отображения TabbedView


from PyQt4.QtGui import QMainWindow, QMdiArea

class MainWnd(QMainWindow):
    def __init__(self, parent=None):

&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XEkSH9xfPcy9d5xh2qaRWYZRbxg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XEkSH9xfPcy9d5xh2qaRWYZRbxg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XEkSH9xfPcy9d5xh2qaRWYZRbxg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XEkSH9xfPcy9d5xh2qaRWYZRbxg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/8_zZebFqqos" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/09/qmdiarea.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UNQHw4fip7ImA9WhdbFU4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-3097200675826924373</id><published>2011-06-06T22:39:00.008+04:00</published><updated>2011-10-13T23:48:11.236+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T23:48:11.236+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="PyWin32" /><title>Мелкие грабли при работе с PyWin32</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/3097200675826924373/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/06/pywin32.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/3097200675826924373?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/3097200675826924373?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/zLDa5ncU5MU/pywin32.html" title="Мелкие грабли при работе с PyWin32" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">

Первые грабли

Возникла необходимость написать простую службу Windows. Для этой цели была избрана известная библиотека PyWin32. На просторах интернета было найдено несколько релевантных примеров и быстренько слеплена служба. Тут я напоролся на первую проблему. 




Симптомы

Служба устанавливается, но не запускается. Функция win32serviceutil.StartService падает с исключением win32service.error 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-mKK9KFgg_h3ABbC_uMttfUHeRA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-mKK9KFgg_h3ABbC_uMttfUHeRA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-mKK9KFgg_h3ABbC_uMttfUHeRA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-mKK9KFgg_h3ABbC_uMttfUHeRA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/zLDa5ncU5MU" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/06/pywin32.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MMQXc_eyp7ImA9WhdbFUw.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-6075113304751359723</id><published>2011-04-02T10:11:00.018+04:00</published><updated>2011-10-13T17:11:20.943+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T17:11:20.943+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="тестирование" /><category scheme="http://www.blogger.com/atom/ns#" term="unittest" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="automation" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="ui" /><category scheme="http://www.blogger.com/atom/ns#" term="must have" /><category scheme="http://www.blogger.com/atom/ns#" term="GUI" /><category scheme="http://www.blogger.com/atom/ns#" term="интерфейс" /><title>Тестирование пользовательского интерфейса в PyQt</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/6075113304751359723/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2011/04/pyqt.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/6075113304751359723?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/6075113304751359723?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/iITaicSBraI/pyqt.html" title="Тестирование пользовательского интерфейса в PyQt" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-kQArpylUlns/TZbKJEVipxI/AAAAAAAAAFQ/0U_E5DqhIDE/s72-c/tcalc1.png" height="72" width="72" /><thr:total>0</thr:total><content type="html">Мне всегда была интересна тема автоматизации тестирования GUI, ибо задача, мягко скажем нетривиальная. А сейчас возник практический интерес к тестированию UI приложений на PyQT.

Как выяснилось, разработчики впихнули в QT целый фреймворк для автоматического тестирования, который в том числе умеет и эмулировать внешние действия пользователя на интерфейсе. Это называется QtTestLib. Другие 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6pSrmdbFMRvH2lbjju9AL0nVJWg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6pSrmdbFMRvH2lbjju9AL0nVJWg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6pSrmdbFMRvH2lbjju9AL0nVJWg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6pSrmdbFMRvH2lbjju9AL0nVJWg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/iITaicSBraI" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2011/04/pyqt.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MBR3Y4fyp7ImA9WhdbFUw.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-2969121529629556821</id><published>2010-06-09T12:43:00.004+04:00</published><updated>2011-10-13T17:10:56.837+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T17:10:56.837+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="инструмент" /><category scheme="http://www.blogger.com/atom/ns#" term="must have" /><category scheme="http://www.blogger.com/atom/ns#" term="refactoring" /><category scheme="http://www.blogger.com/atom/ns#" term="дублирование кода" /><title>Поиск похожих участков в питоновском коде</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/2969121529629556821/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/06/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2969121529629556821?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2969121529629556821?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/IIZh8S2Y_mA/blog-post.html" title="Поиск похожих участков в питоновском коде" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Когда-то довольно давно отложилось в памяти, что существует полезный инструмент, способный качественно найти в коде на python похожие куски для их дальнейшего рефакторинга.

Вчера выдалась относительно свободная минута, и я решил его таки найти. После долгих поисков наконец нарыл. Итак, знакомимся - CloneDigger



Устанавливается через easy_install: 
easy_install -U clonedigger

Доступен также 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OpQPGPWyUcFL47ccaPLjgH6gQos/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OpQPGPWyUcFL47ccaPLjgH6gQos/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OpQPGPWyUcFL47ccaPLjgH6gQos/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OpQPGPWyUcFL47ccaPLjgH6gQos/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/IIZh8S2Y_mA" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/06/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UFQ3gyeyp7ImA9WhdbFU4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-7693550285980387925</id><published>2010-05-27T17:43:00.025+04:00</published><updated>2011-10-13T23:46:52.693+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T23:46:52.693+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="модель-представление" /><category scheme="http://www.blogger.com/atom/ns#" term="модели Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="model-view" /><category scheme="http://www.blogger.com/atom/ns#" term="Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="SQL" /><title>PyQt: Добавление записей в связанную модель (relationModel) во время редактирования записи основной</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/7693550285980387925/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/05/pyqt-relationmodel.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7693550285980387925?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7693550285980387925?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/tcML5tAeFVw/pyqt-relationmodel.html" title="PyQt: Добавление записей в связанную модель (relationModel) во время редактирования записи основной" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">


Абстрактная задача

Существует таблица main, содержащая помимо прочего поле-ссылку на справочник classifier_id. Код на sqlite:

CREATE TABLE classifier
(
    id INTEGER NOT NULL,
    name TEXT
);

CREATE TABLE main 
(
    id INTEGER NOT NULL,
    name TEXT,
    classifier_id INTEGER REFERENCES classisfier (id)
);

Необходимо написать на PyQt диалог редактирования записи таблицы main с 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/dJORFFTwiV5_gVVssDgMvkcJvHU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dJORFFTwiV5_gVVssDgMvkcJvHU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/dJORFFTwiV5_gVVssDgMvkcJvHU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dJORFFTwiV5_gVVssDgMvkcJvHU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/tcML5tAeFVw" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/05/pyqt-relationmodel.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAGQnszeSp7ImA9WhdUGU0.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-1624064082328009831</id><published>2010-05-08T03:34:00.009+04:00</published><updated>2011-10-06T15:32:03.581+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-06T15:32:03.581+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="виртуализация" /><category scheme="http://www.blogger.com/atom/ns#" term="инструмент" /><title>VirtualBox</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/1624064082328009831/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/05/virtualbox.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/1624064082328009831?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/1624064082328009831?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/YoxkgqitcQU/virtualbox.html" title="VirtualBox" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">Недавно потребовалось протестировать программку на чистой Windows XP. Дома на машине стоит Windows 7 x64, поэтому пришлось посмотреть в сторону виртуальных машин. На слуху как-то больше VMWare, но мне она почему-то не нравится. Остались от нее какие-то смутные негативные впечатления, когда игрался несколько лет назад.

Кто-то из знакомых в разговоре вскользь упомянул VirtualBox, причем хорошо 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3_JhQ2a0p976JNpiHobw84i685U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3_JhQ2a0p976JNpiHobw84i685U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3_JhQ2a0p976JNpiHobw84i685U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3_JhQ2a0p976JNpiHobw84i685U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/YoxkgqitcQU" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/05/virtualbox.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8BQX89fCp7ImA9WhdUGUo.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-2651407328420222112</id><published>2010-04-29T02:02:00.010+04:00</published><updated>2011-10-07T11:50:50.164+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-07T11:50:50.164+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="метаданные" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="sqlite" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="SQL" /><title>Детальные метаданные sqlite3</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/2651407328420222112/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/04/sqlite3_29.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2651407328420222112?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2651407328420222112?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/4FqsnKiwlq4/sqlite3_29.html" title="Детальные метаданные sqlite3" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">В одном из предыдущих постов я описывал, как получить список таблиц в базе sqlite, и сокрушался, что непонятно, как получить детальную информацию о них. 

Знающие люди ткнули носом в раздел документации sqlite, где описан набор прагм (pragma) для получения исчерпывающей информации о структуре базы. Подробно расписывать не буду, разработчики sqlite прекрасно сделали это сами.

Как выяснилось, эта 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HzuvKEhm6yc6gkFA9XztuwQdRmQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HzuvKEhm6yc6gkFA9XztuwQdRmQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HzuvKEhm6yc6gkFA9XztuwQdRmQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HzuvKEhm6yc6gkFA9XztuwQdRmQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/4FqsnKiwlq4" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/04/sqlite3_29.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UARXk4eSp7ImA9WhdbFU4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-7377027723977687201</id><published>2010-04-29T00:56:00.014+04:00</published><updated>2011-10-13T23:47:24.731+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T23:47:24.731+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="модель-представление" /><category scheme="http://www.blogger.com/atom/ns#" term="модели Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="model-view" /><category scheme="http://www.blogger.com/atom/ns#" term="маппинг виджетов" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Нюансы разработки GUI базы данных на PyQt</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/7377027723977687201/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/04/gui-pyqt.html#comment-form" title="Комментарии: 1" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7377027723977687201?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/7377027723977687201?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/zXX-gfRWG_0/gui-pyqt.html" title="Нюансы разработки GUI базы данных на PyQt" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>1</thr:total><content type="html">При разработке интерфейса к базе данных на PyQt существует несколько моментов, за которыми нужно следить, чтобы программа вела себя соответственно ожиданиям. Их немного и они, в общем-то, логичны, но с непривычки что-то можно упустить и долго ломать голову, почему нихрена не работает. 

Мне попортили определенное количество крови следующие вещи:


Неотъемлемой частью инициализации 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ppUFDJ3YBRdIS0LmQA6OUr8VLwM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ppUFDJ3YBRdIS0LmQA6OUr8VLwM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ppUFDJ3YBRdIS0LmQA6OUr8VLwM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ppUFDJ3YBRdIS0LmQA6OUr8VLwM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/zXX-gfRWG_0" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/04/gui-pyqt.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QDRHg8eCp7ImA9WhdbFUw.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-4478577511669927109</id><published>2010-04-24T23:48:00.011+04:00</published><updated>2011-10-13T17:09:35.670+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T17:09:35.670+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="ui" /><category scheme="http://www.blogger.com/atom/ns#" term="GUI" /><category scheme="http://www.blogger.com/atom/ns#" term="диалог" /><category scheme="http://www.blogger.com/atom/ns#" term="интерфейс" /><title>PyQt: Генерация кода по ресурсу интерфейса</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/4478577511669927109/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/04/pyqt.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/4478577511669927109?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/4478577511669927109?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/zKBx4s7Wzss/pyqt.html" title="PyQt: Генерация кода по ресурсу интерфейса" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">В подавляющем большинстве инструментов для создания GUI, которые мне доводилось использовать, для нормальной работы программы положено из ресурса некоторым образом сгенерировать код. Естественно, полученную рыбу надо наполнить прикладной логикой.

Веселуха начинается, когда возникает необходимость изменить ресурс. Путей при этом два: описания новых контролов ресурса добавлять в ранее 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OfcFEAHMZKO--k3V5wWGblFgRAo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OfcFEAHMZKO--k3V5wWGblFgRAo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OfcFEAHMZKO--k3V5wWGblFgRAo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OfcFEAHMZKO--k3V5wWGblFgRAo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/zKBx4s7Wzss" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/04/pyqt.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4FSXg7eyp7ImA9WhdUGUo.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-1202148169947550758</id><published>2010-04-24T20:23:00.007+04:00</published><updated>2011-10-07T11:51:58.603+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-07T11:51:58.603+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="метаданные" /><category scheme="http://www.blogger.com/atom/ns#" term="sqlite" /><category scheme="http://www.blogger.com/atom/ns#" term="SQL" /><title>Метаданные sqlite3</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/1202148169947550758/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/04/sqlite3.html#comment-form" title="Комментарии: 2" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/1202148169947550758?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/1202148169947550758?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/JFP2OSQcpmw/sqlite3.html" title="Метаданные sqlite3" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-8CfdsmOme30/S9NDhSPduiI/AAAAAAAAAFQ/-b3jJ4idklM/s72-c/sqlite_master.png" height="72" width="72" /><thr:total>2</thr:total><content type="html">Как выяснилось, у sqlite очень просто получить список существующих  таблиц, индексов, представлений и триггеров.


Например, создадим структуру:

CREATE TABLE IF NOT EXISTS table1 (id integer, name text);
CREATE INDEX IF NOT EXISTS index1 ON table1 (name);
CREATE VIEW IF NOT EXISTS view1 AS SELECT name FROM table1;
CREATE TRIGGER IF NOT EXISTS trigger1  DELETE ON table1 
BEGIN 
  select * from 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EAwLSANDaPAXu8LcpjkjeQ1ntkg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EAwLSANDaPAXu8LcpjkjeQ1ntkg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EAwLSANDaPAXu8LcpjkjeQ1ntkg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EAwLSANDaPAXu8LcpjkjeQ1ntkg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/JFP2OSQcpmw" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/04/sqlite3.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UCQXc-fip7ImA9WhdbFU4.&quot;"><id>tag:blogger.com,1999:blog-6428567201714816130.post-2383123235941104330</id><published>2010-04-24T20:09:00.002+04:00</published><updated>2011-10-13T23:47:40.956+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-13T23:47:40.956+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="модель-представление" /><category scheme="http://www.blogger.com/atom/ns#" term="модели Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="PyQt" /><category scheme="http://www.blogger.com/atom/ns#" term="model-view" /><category scheme="http://www.blogger.com/atom/ns#" term="sqlite" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="SQL" /><title>Глюк стандартных SQL-моделей PyQt4</title><link rel="replies" type="application/atom+xml" href="http://pythonistaa.blogspot.com/feeds/2383123235941104330/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://pythonistaa.blogspot.com/2010/04/sql-pyqt4.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2383123235941104330?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6428567201714816130/posts/default/2383123235941104330?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ClassQsqliteblogqobject/~3/UDEohdkci08/sql-pyqt4.html" title="Глюк стандартных SQL-моделей PyQt4" /><author><name>Дмитрий Касацкий</name><uri>https://profiles.google.com/101292199919221407505</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-m_X0o_Wf6K0/AAAAAAAAAAI/AAAAAAAAAG0/vxuR9PjpDrU/s512-c/photo.jpg" /></author><thr:total>0</thr:total><content type="html">При написании простенькой базы данных (PyQt4+sqlite) наткнулся на неприятный глюк связки QSqlTableModel и QTableView: при добавлении во вьюху новых строк активна всегда только первая строка и в базу ничего не пишется.

Выяснилось, что PyQt ни при чем, проблему создавало еще одно соединение с базой средствами стандартного питоновского модуля sqlite3, использовавшееся вспомогательным функционалом. 
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6fUNqMmVYQYT1esBCS_qM6LkkUA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6fUNqMmVYQYT1esBCS_qM6LkkUA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6fUNqMmVYQYT1esBCS_qM6LkkUA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6fUNqMmVYQYT1esBCS_qM6LkkUA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ClassQsqliteblogqobject/~4/UDEohdkci08" height="1" width="1"/&gt;</content><feedburner:origLink>http://pythonistaa.blogspot.com/2010/04/sql-pyqt4.html</feedburner:origLink></entry></feed>

