<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-618236974937224190</id><updated>2024-09-20T23:52:56.211+02:00</updated><category term="django"/><category term="python"/><category term="tips&#39;n tricks"/><category term="webdev"/><category term="djang-lfs"/><category term="django-lfs"/><category term="e-commerce"/><category term="perl"/><category term="шпаргалки"/><category term="JavaScript"/><category term="linux"/><category term="models"/><category term="ошибки"/><category term="ORM"/><category term="errors"/><category term="jQuery"/><category term="sqlite"/><category term="глюки"/><category term="совместимость версий"/><category term="css framework"/><category term="nginx"/><category term="postgres"/><category term="windows"/><category term="верстка"/><category term="решение проблем"/><category term="туториал"/><category term="хостинг"/><category term="CPAN"/><category term="Kickstart"/><category term="ajax"/><category term="apache"/><category term="bitbucket"/><category term="bugs"/><category term="captcha"/><category term="debian"/><category term="devops"/><category term="django-piston"/><category term="django-rest-framework"/><category term="flatpages"/><category term="foundation"/><category term="jino"/><category term="json"/><category term="libgd"/><category term="mod_wsgi"/><category term="mysql"/><category term="oracle"/><category term="php"/><category term="python3"/><category term="rest api"/><category term="sql"/><category term="tutorial"/><category term="twitter bootstrap"/><category term="unicode"/><category term="utf8"/><category term="virustotal"/><category term="vps"/><category term="web-сервер"/><category term="wysiwyg"/><category term="ВКонтакте"/><category term="авторизация"/><category term="авторизация пользователей"/><category term="бд"/><category term="доработка напильником"/><category term="копирайт"/><category term="креатив"/><category term="миграция"/><category term="напоминалка"/><category term="настройка"/><category term="перепост"/><category term="печать"/><category term="приложения django"/><category term="субд"/><category term="трюки"/><category term="утилиты"/><category term="хостинги"/><category term="шаблоны"/><title type='text'>Разработка после тестирования</title><subtitle type='html'>статьи программиста-тестировщика или тестировщика-программиста ...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>75</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-3925290801307818343</id><published>2019-12-31T07:19:00.001+02:00</published><updated>2019-12-31T07:21:59.511+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="errors"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>No module name &#39;_ctypes&#39; while creating new virtualenv</title><content type='html'>When I tried to create virtualenv with python3.7 ( &lt;br /&gt;
&lt;pre&gt;virtualenv -p /usr/local/bin/python3.7&lt;/pre&gt; on one of my fresh VPS I faced &lt;pre&gt;no module name &#39;_ctypes&#39;&lt;/pre&gt;

You should perform these steps to fix it:

&lt;pre&gt;
sudo apt-get update
sudo apt-get install libffi-dev
&lt;/pre&gt;

If you still have same error then you probably installed python3.7 by yourself from source codes. If so just repeat this installation: 

&lt;pre&gt;
cd /usr/src
wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz
sudo tar xzf Python-3.7.4.tgz
cd Python-3.7.4
sudo ./configure --enable-optimizations
sudo make altinstall
&lt;/pre&gt;

:hint

if you have more than one cpu core, then you can speed up &lt;i&gt;make&lt;/i&gt; stage by: &lt;pre&gt;sudo make altinstall -j &amp;lt;number_of_cores&amp;gt;&lt;/pre&gt;

:hint

&lt;pre&gt;cat /proc/cpuinfo&lt;/pre&gt; - shows you the information about your CPUs</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/3925290801307818343/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/no-module-name-ctypes-whili-creating.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/3925290801307818343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/3925290801307818343'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/no-module-name-ctypes-whili-creating.html' title='No module name &#39;_ctypes&#39; while creating new virtualenv'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-5791867416957325078</id><published>2019-12-18T10:20:00.000+02:00</published><updated>2019-12-18T10:21:02.975+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="postgres"/><title type='text'>postgresql - permission denied for sequence </title><content type='html'>Если ты столкнулся с  %%permission denied for sequence %%, то значит, что ты используешь  в табличке автоинкремент ( тип %%SERIAL%% или %%BIGSERIAL%% ) и тебе нужны соответствующие гранты соответствуюшему пользователю:

%%grant all privileges on sequence &lt;sequence_name&gt; to &lt;youruser&gt;%%</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/5791867416957325078/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/postgresql-permission-denied-for_18.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5791867416957325078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5791867416957325078'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/postgresql-permission-denied-for_18.html' title='postgresql - permission denied for sequence '/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-6108056224042884036</id><published>2019-12-18T10:17:00.003+02:00</published><updated>2019-12-18T10:20:49.370+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="postgres"/><title type='text'>postgresql - permission denied for relation</title><content type='html'>Если ты столкнулся с %%permission denied for relation%% , то попробуй дать соответствующему юзеру:

%%grant all privileges on  table &lt;tablename&gt; to &lt;username&gt;;%%</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/6108056224042884036/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/postgresql-permission-denied-for.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/6108056224042884036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/6108056224042884036'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/postgresql-permission-denied-for.html' title='postgresql - permission denied for relation'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-714415012745120982</id><published>2019-12-04T09:29:00.001+02:00</published><updated>2019-12-04T09:29:54.829+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python3"/><title type='text'>python3 f-string &#39;invalid syntax&#39;</title><content type='html'>If you faced &#39;invalid syntax&#39; while using f-strings in python3 
then you probably have ancient python version installed.

f-strings feature appeared in 3.6 

So you have to install a new python to be able to use f-strings in your code:

For example, you are in Ubuntu ( or some other deb-based distrib ):

&lt;blockquote&gt;sudo wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz
sudo tar xzf Python-3.7.4.tgz

cd Python-3.7.4
sudo ./configure --enable-optimizations
sudo make altinstall # not to replace default python&lt;/blockquote&gt;

</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/714415012745120982/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/python3-f-string-invalid-syntax.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/714415012745120982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/714415012745120982'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2019/12/python3-f-string-invalid-syntax.html' title='python3 f-string &#39;invalid syntax&#39;'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-4466159913661034812</id><published>2019-10-30T08:34:00.000+02:00</published><updated>2019-10-30T08:34:54.945+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="ORM"/><title type='text'>Raw query must include the primary key</title><content type='html'>Как и любое достижение прогресса ORM-ы в каких-то кейсах хороши и удобны, а в некоторые моменты - раздражают.

Например, когда речь о Django и случае, когда ты хочеш выполнить raw-запрос с группировкой ( чтобы не париться с нечевидными annotate и импортом нужных агрегатных функций ) .

Пример: &lt;blockquote&gt;r = CourseStudent.objects.raw(&quot;select course_id, count(*) as c from coursestudent group by course_id order by c&quot;)&lt;/blockquote&gt;

В ответ мы видим: &lt;blockquote&gt;Raw query must include the primary key&lt;/blockquote&gt;

WTF? Как я вам воткну pk в запрос с группировкой по произвольному ключу ?

К счастью, обойти просто - вот такой запрос спокойно отработает:

&lt;blockquote&gt;r = CourseStudent.objects.raw(&quot;select course_id as id, count(*) as c from coursestudent group by course_id order by c&quot;)&lt;/blockquote&gt; - мы немного схимичили, и навесили на произвольный ключ alias, такой же как pk таблицы, к которой мы делаем наш произвольный запрос
</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/4466159913661034812/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2019/10/raw-query-must-include-primary-key.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/4466159913661034812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/4466159913661034812'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2019/10/raw-query-must-include-primary-key.html' title='Raw query must include the primary key'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-7259659192455567089</id><published>2019-10-29T08:55:00.000+02:00</published><updated>2019-10-29T08:55:49.781+02:00</updated><title type='text'>Migration is applied before its dependency on database</title><content type='html'>Разбираемся с ошибкой &lt;blockquote&gt;Migration B is applied before its dependency A on database&lt;/blockquote&gt;

Django version 1.11

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


</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/7259659192455567089/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2019/10/migration-is-applied-before-its.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/7259659192455567089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/7259659192455567089'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2019/10/migration-is-applied-before-its.html' title='Migration is applied before its dependency on database'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-1371294364680079126</id><published>2016-01-16T14:51:00.001+02:00</published><updated>2019-12-31T07:22:22.289+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="perl"/><category scheme="http://www.blogger.com/atom/ns#" term="unicode"/><category scheme="http://www.blogger.com/atom/ns#" term="utf8"/><title type='text'>Еще раз про юникод в perl и злосчастный Wide character in subroutine entry</title><content type='html'>Многие perl скриптеры &amp;nbsp;порой впадают в ступор от &lt;code&gt;Wide character in subroutine entry&lt;/code&gt;.
Хорошо, если знают хотя бы примерно о том, что такое &lt;code&gt;Wide character&lt;/code&gt;, хуже , если нет.
Хорошо, если начинают копать матчасть и разбираются с в общем-то нехитрой работой с юникодом в perl, хуже, если начинают наобум тыкать в &lt;code&gt;use utf8&lt;/code&gt;, &lt;code&gt;encode/decode&lt;/code&gt;... На выходе порой может получиться забавная инструкция с кучей вызовов на всякий случай.. она может даже будет работать, но подобный модуль будет доставлять всем вокруг головную боль.

Итак, все просто:

1. если имеешь дело с данными из внешнего источника - проверяй их перед употреблением на &lt;code&gt;is_utf8&lt;/code&gt; и дальше действуй по обстоятельствам: либо кодируй, либо декодируй - но осознанно.
2. если имеешь дело со строковыми константами , то достаточно сказать &lt;code&gt;use utf8&lt;/code&gt; , чтобы для интерпретатора все константы скрипта были помечены не как последовательность байт, а именно как юникод-строка.
3. чтобы перевести в последовательность байт из юникода - decode
4. чтобы перевести из последовательности байт в юникод - encode

помните о том, кто будет вас дергать и описывайте свои входы и выходы а также свою политику относительно внутренней работы со строками ( работаете как с последовательностю байт или как со юникод-строками ) и все будет хорошо.</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/1371294364680079126/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2016/01/perl-wide-character-in-subroutine-entry.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1371294364680079126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1371294364680079126'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2016/01/perl-wide-character-in-subroutine-entry.html' title='Еще раз про юникод в perl и злосчастный Wide character in subroutine entry'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-1854039822123444881</id><published>2013-07-18T19:20:00.000+03:00</published><updated>2013-07-18T19:20:24.902+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><category scheme="http://www.blogger.com/atom/ns#" term="верстка"/><title type='text'>Классическая проблема верстки - выравнивание блоков</title><content type='html'>Часто встречается ситуация, когда некий контейнер &quot;набивается&quot; float-ом дочерними элементами .

На макете все красиво и ровно. На практике, после того как начинается работа с реальным контентом (например содержимое категории товаров в магазине), то однотипные блоки получаются разными по высоте.

Проблему можно решить принудительным транкейтом содержимого, подбором &quot;максимальной&quot; фиксированной высоты или javascript-ом.

Пример кода, решающего подобную проблему (используется jQuery):

&lt;pre&gt;
&lt;code class=&quot;js&quot;&gt;
//делаем высоту всех .thumbnail одинаковой
   var  max_height = 0;
 $(&#39;.thumbnail&#39;).each(function(){
    h = $(this).height();
   if(h &gt; max_height){
     max_height = h;
    };
   });
 $(&#39;.thumbnail&#39;).css(&#39;height&#39;,max_height);
&lt;/code&gt;
&lt;/pre&gt;

Этот код хорошо отработает , например , в IE, а вот Chrome могут быть проблемы, если в .thumnail внутри есть изображение.

На момент вычисления height оно еще может быть не загруженным и поэтому полученные величины height и width могут очень удивить верстальщика :)

Поэтому код надо модифицировать , например, вот так:

&lt;pre&gt;
&lt;code class=&quot;js&quot;&gt;
$(document).ready(function(){
//делаем высоту всех .thumbnail одинаковой только после полной загрузки всей страницы
   var  max_height = 0;
 $(&#39;.thumbnail&#39;).each(function(){
    h = $(this).height();
   if(h &gt; max_height){
     max_height = h;
    };
   });
 $(&#39;.thumbnail&#39;).css(&#39;height&#39;,max_height);
});
&lt;/code&gt;
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/1854039822123444881/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1854039822123444881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1854039822123444881'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/blog-post.html' title='Классическая проблема верстки - выравнивание блоков'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-8999765666290932128</id><published>2013-07-09T18:59:00.001+03:00</published><updated>2013-07-09T19:00:30.662+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><category scheme="http://www.blogger.com/atom/ns#" term="windows"/><title type='text'>Unable to find vcvarsall.bat</title><content type='html'>Часто при установке некоторых python-библиотек (PIL, django-imagestore .. ) под windows возникает ошибка:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Unable to find vcvarsall.bat&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
Причина отсутствии или невозможности при установке найти нужный Сишный компилятор, который как правило есть &amp;nbsp;в поставке MS VS.&lt;br /&gt;
&lt;br /&gt;
Для решения проблемы совсем необязательно ставить &quot;студию&quot;. Можно обойтись компилятором mingw:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;качаем &lt;a href=&quot;http://sourceforge.net/projects/mingw/?source=dlp&quot; target=&quot;_blank&quot;&gt;отсюда&lt;/a&gt; и ставим&lt;/li&gt;
&lt;li&gt;скачиваем нужную python - библиотеку и выполняем для ее setup.py :&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;
setup.py install build --compiler=mingw32
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
Перед этим не забудьте прописать путь к mingw32.exe в PATH (например C:\mingw\bin)&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/8999765666290932128/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/unable-to-find-vcvarsallbat.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/8999765666290932128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/8999765666290932128'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/unable-to-find-vcvarsallbat.html' title='Unable to find vcvarsall.bat'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total><georss:featurename>Москва, Россия</georss:featurename><georss:point>55.7512419 37.6184217</georss:point><georss:box>55.1792854 36.327528199999996 56.323198399999995 38.9093152</georss:box></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-6102475977386850748</id><published>2013-07-04T16:02:00.001+03:00</published><updated>2013-07-12T14:11:11.250+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="django-rest-framework"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>django-rest-framework - некоторые особенности</title><content type='html'>Как и обещал ранее дамплю все грабли и особенности , которые возникают в ходе освоения этого фреймфорка.&lt;br /&gt;
&lt;br /&gt;
Сразу отмечу, что авторы этого приложения большие молодцы - документация на фреймворк сделана в виде пошагового туториала - фактически онлайн учебника. На первых шагах все делается стандартными механизмами. И дальше, по мере продвижения, авторы упрощают код с помощью многочисленных &quot;плюшек&quot; , которые предоставляет их приложение. Советую для лучшего понимания и во избежание последующего недопонимания :) именно так и поступать, а не копипастить конечные синтаксические конструкции.&lt;br /&gt;
Хотя при этом могут и проблемы возникнуть . Например, на одном из шагов авторы предлагают реализовать rest-вьюхи &amp;nbsp;как обычные function-based django views, сопровождая их декоратором api_view. Этот шаг - исключение и его лучше пропустить, сразу перейдя к class based views , иначе возникнет ошибка:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;exception_value&quot; style=&quot;color: #666666; font-family: sans-serif; font-size: 1.5em; margin-bottom: 10px; margin-top: 10px; padding: 0px; white-space: pre-wrap;&quot;&gt;Cannot apply DjangoModelPermissions on a view that does not have `.model` or `.queryset` property.&lt;/pre&gt;
&lt;pre class=&quot;exception_value&quot; style=&quot;margin-bottom: 10px; margin-top: 10px; padding: 0px;&quot;&gt;&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;Но и после перехода в class-based views не забываем указывать model или queryset в полях вьюшного класса.&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;h3&gt;
Unicode&lt;/h3&gt;
&lt;div&gt;
Для того, чтобы в отдаваемом REST-ом контенте корректно отображался Unicode необходимо в settings явно прописать UnicodeJSONRenderer.&lt;/div&gt;
&lt;div&gt;
Например:&lt;/div&gt;

&lt;pre&gt;
&lt;code class=&quot;python&quot;&gt;
REST_FRAMEWORK = {
 
    &#39;DEFAULT_RENDERER_CLASSES&#39;: (
        &#39;rest_framework.renderers.UnicodeJSONRenderer&#39;,
    )
}
&lt;/code&gt;
&lt;/pre&gt;

&lt;pre class=&quot;exception_value&quot; style=&quot;margin-bottom: 10px; margin-top: 10px; padding: 0px;&quot;&gt;&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/6102475977386850748/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/django-rest-framework.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/6102475977386850748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/6102475977386850748'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/django-rest-framework.html' title='django-rest-framework - некоторые особенности'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-1410840788693289538</id><published>2013-07-04T09:11:00.000+03:00</published><updated>2013-07-04T09:11:50.851+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="django-piston"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="rest api"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>Выбор решения для организации API на django-сайте</title><content type='html'>Возникла задача в одном из моих django-проектов предоставить API для взаимодействия с некоей внешней системой.&lt;br /&gt;
Первоначальный выбор пал на django-piston. Реализовать операции read-доступа к объектам БД удалось довольно быстро, но вот с операцией создания объекта начались проблемы, частично решив которые и получив новые , решил выбрать другое решение.. Уж больно надоело патчить чужую библиотеку.&lt;br /&gt;
Другое решение - это Django Rest Framework. Знакомство с отзывами и документацией обещает менее нервную разработку. К непосредственной попытке использования приступлю на днях.&lt;br /&gt;
Постараюсь не забыть задокументировать здесь все особенности и подводные камни, если таковые найдутся :)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/1410840788693289538/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/api-django.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1410840788693289538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1410840788693289538'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/07/api-django.html' title='Выбор решения для организации API на django-сайте'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-5299125423419613683</id><published>2013-05-29T08:45:00.003+03:00</published><updated>2013-05-29T08:45:48.395+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="virustotal"/><category scheme="http://www.blogger.com/atom/ns#" term="креатив"/><title type='text'>django: форма обратной связи с аттачами и проверкой на вирусы</title><content type='html'>&lt;h2&gt;
Предыстория&lt;/h2&gt;
Недавно получил от одного своего постоянного клиента заказ на следующую доработку: &quot;нужно доработать форму обратной связи для возможности отправки файлов клиентами&quot;.&lt;br /&gt;
&lt;br /&gt;
В процессе обсуждений &amp;nbsp;выяснилось, что файлов надо аттачить &quot;сколько хочешь&quot;.&lt;br /&gt;
&lt;br /&gt;
А чтобы заказчик не &quot;словил вирусняк&quot; через эти самые аттачи , я решил реализовать сканирование.&lt;br /&gt;
&lt;br /&gt;
Было 2 варианта:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;настроить на серваке (linux) какой-нибудь , желательно бесплатный , антивирусный демон&amp;nbsp;&lt;/li&gt;
&lt;li&gt;использовать API какого-нибудь авторитетного онлайн сервиса&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Я остановился на втором варианте, тем более что был немного знаком с Virustotal.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Бегло ознакомился с &lt;a href=&quot;https://www.virustotal.com/ru/documentation/public-api/&quot; target=&quot;_blank&quot;&gt;доками на его API&lt;/a&gt;&amp;nbsp;.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Проверил работоспособность его тестовых примеров &amp;nbsp;- все ок.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
И приступил к &quot;допиливанию&quot; имеющейся формы обратной связи.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Как только причешу код , чтобы было не стыдно опубликовать на bitbucket, то детально опишу реализацию.&lt;br /&gt;
&lt;br /&gt;
Кому не терпится - пишите, торопИте :)&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/5299125423419613683/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/05/django.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5299125423419613683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5299125423419613683'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/05/django.html' title='django: форма обратной связи с аттачами и проверкой на вирусы'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-1395979904059855898</id><published>2013-04-29T21:18:00.001+03:00</published><updated>2013-04-29T21:18:42.886+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="django-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><category scheme="http://www.blogger.com/atom/ns#" term="доработка напильником"/><title type='text'>django-lfs: особенности работы со скидками</title><content type='html'>Текущая стабильная версия 0.7.7&lt;br /&gt;
&lt;br /&gt;
В &lt;b&gt;django-lfs&lt;/b&gt; есть два механизма работы со скидками:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;назначать скидку каждому товару отдельно в карточке товара&lt;/li&gt;
&lt;li&gt;создавать глобальные скидки, которые действуют в зависимости от критериев (например общая сумма покупки в корзине) - данные скидки применяются не к отдельным &amp;nbsp;товарам , &amp;nbsp;а к всему содержимому корзины.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Особенность в том, что при наличии обоих скидок они суммируются.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
При использовании данной и более младших версий &lt;b&gt;django-lfs вместе &lt;/b&gt;с django &amp;gt;= 1.4 есть проблема с интерфейсом управления - &amp;nbsp;а именно бага при работе с критериями. Суть ошибки и как &amp;nbsp;ее решить &amp;nbsp;я уже описывал &lt;a href=&quot;http://dev-after-test.blogspot.ru/2012/06/django-lfs-3.html&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Кроме того, глобальным ссылкам не хватает развернутого описания . Например, для того, чтобы вывести страницу со скидками, где было бы содержательно описана суть каждой из них.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Доработать не трудно.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;добавляем нужное поле в Discount&amp;nbsp;&lt;/li&gt;
&lt;li&gt;добавляем колонку в таблицу discount_discount (если база уже существует) или пересоздаем базу (если старого контента не жалко :)&lt;/li&gt;
&lt;li&gt;добавляем нужный html-шаблон для страницы со списком скидок&lt;/li&gt;
&lt;li&gt;добавляем view, которая будет рендерить этот шаблон&lt;/li&gt;
&lt;li&gt;добавляем url, по которому это view будет &quot;дергаться&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
кому нужен патч - пишите.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/1395979904059855898/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/04/django-lfs.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1395979904059855898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1395979904059855898'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/04/django-lfs.html' title='django-lfs: особенности работы со скидками'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-7644748027152650200</id><published>2013-04-12T20:28:00.002+03:00</published><updated>2013-04-12T20:28:46.918+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="django-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="e-commerce"/><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><category scheme="http://www.blogger.com/atom/ns#" term="windows"/><title type='text'>django-lfs: установка на Windows 7</title><content type='html'>Установка django-lfs &amp;nbsp;подробно описана &lt;a href=&quot;http://docs.getlfs.com/en/latest/introduction/installation.html&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Но у установки под windows есть несколько особенностей, которые не описаны на официальном сайте&lt;br /&gt;
&lt;br /&gt;
Исходные данные:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;windows7 64 bin&lt;/li&gt;
&lt;li&gt;python 2.7 , установленный , например в c:\Python27&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Требуется установить django-lfs (на текущий момент версия 0.7.7)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;качаем инсталлятор&amp;nbsp;&lt;a class=&quot;reference external&quot; href=&quot;http://pypi.python.org/pypi/django-lfs&quot; style=&quot;color: #005b81; text-decoration: none;&quot;&gt;http://pypi.python.org/pypi/django-lfs&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;распаковываем куда нам нужно&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;cd lfs-installer&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;&lt;a href=&quot;http://downloads.buildout.org/2/bootstrap.py&quot; target=&quot;_blank&quot;&gt;качаем правильный bootstrap.py&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;python bootstrap.py&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;&lt;a href=&quot;http://effbot.org/downloads/PIL-1.1.7.win32-py2.7.exe&quot; target=&quot;_blank&quot;&gt;качаем win-инсталлятор для библиотеки PI&lt;/a&gt;L (так как установщик ругнется на отсутствие батника &lt;b&gt;vcvarsall.bat&lt;/b&gt;)&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;создаем ключ в реестре &lt;i&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Python\PythonCore\2.7\InstallPath&lt;/i&gt; со значением, которое копируем из ключа&amp;nbsp; &lt;i&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.7\InstallPath &amp;nbsp;&lt;/i&gt;- без этой манипуляции инсталлятор PIL &quot;ругнется&quot; &amp;nbsp;&lt;i&gt;&lt;b&gt;Python27 not found&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;удаляем Pillow из списка зависимостей djanfo-lfs (файл:&amp;nbsp;&lt;i&gt;lfs-installer\eggs\django_lfs-0.7.7-py2.7.egg\EGG-INFO\requires&lt;/i&gt;)&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;устанавливаем PIL&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;bin/buildout.exe -v&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;указываем параметры доступа к базе данных (предполагается, что она уже создана) &amp;nbsp;в settings to lfs_project/settings.py&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;$ bin/django syncdb&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;$ bin/django lfs_init&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;$ bin/django collectstatic&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;$ bin/django runserver&lt;/li&gt;
&lt;li style=&quot;line-height: 1.5em;&quot;&gt;Открываем дефолтный магазин&amp;nbsp;&lt;a class=&quot;reference external&quot; href=&quot;http://localhost:8000/&quot; style=&quot;color: #005b81; text-decoration: none;&quot;&gt;http://localhost:8000&lt;/a&gt;&amp;nbsp;и торгуем :)&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/7644748027152650200/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/04/django-lfs-windows-7.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/7644748027152650200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/7644748027152650200'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/04/django-lfs-windows-7.html' title='django-lfs: установка на Windows 7'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-1302709072259199308</id><published>2013-03-29T08:54:00.003+03:00</published><updated>2013-03-29T08:54:52.108+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="wysiwyg"/><category scheme="http://www.blogger.com/atom/ns#" term="копирайт"/><title type='text'>django-lfs: wysiwyg и копипаст контента с других сайтов</title><content type='html'>В каждом новом веб-проекте встает дилемма - использовать ли wysiwyg в административной части сайта. С одной стороны хочется избавить себя от будущего утомительного контент-менеджмента, который не очень дорого оплачивается (если вообще оплачивается),&amp;nbsp; а с другой - дашь пользователю полноценный &lt;b&gt;wysiwyg&lt;/b&gt; - он вмиг сломает всю верстку и в итоге тебя же и обвинит: &quot;ты мол программист, ты должен был все учесть&quot;...&lt;br /&gt;
&lt;br /&gt;
Каждый раз приходится анализировать, что за пользователи будут рулить сайтом, обучать даже иногда.&lt;br /&gt;
&lt;br /&gt;В общем это проблема не новая. Есть еще одна - смежная с ней. Часто начинающие &quot;контент-менеджеры&quot; сайтов (они же и их владельцы по-совместительству :) не брезгуют простым копипастом контента с сайтов конкурентов, сайтов с понравившимся контентом.. Им невдомек, что есть понятие &quot;&lt;b&gt;копирайт&lt;/b&gt;&quot;, что редактор &quot;не умеет&quot; превращать чужие картинки в свои, что он копирует буквально все, в том числе и внешние ссылки.&lt;br /&gt;
&lt;br /&gt;
Один такой мой клиент, пользующийся интернет-магазином на &lt;b&gt;django-lfs&lt;/b&gt;, ну никак не хотел бросать такую вредную привычку , пришлось запилить ему логику дайнлоада картинок из скопированного куска, вычистку непредусмотренных внешних ссылок .&lt;br /&gt;
&lt;br /&gt;
Везде , где можно был переопредлен обработчик save моделей и в этом обработчике вызывался метод, который скачивает картинки в media, меняет пути на свои локальные, чистит внешние ссылки.&lt;br /&gt;
&lt;br /&gt;
Планирую еще и PIL прикрутить к этому делу, чтобы вотермарки накладывать. Любой каприз, как говорится, за ваши деньги.&lt;br /&gt;
&lt;br /&gt;
p.s. но тырить контент с чужих сайтов, не оставляя ссылок - нехорошо , о чем все мои клиенты честно предупреждаются. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
p.p.s если кого интересует, то могу код причесать и выложить на какой-нибудь bitbucket - пишите.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/1302709072259199308/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/03/django-lfs-wysiwyg.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1302709072259199308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/1302709072259199308'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/03/django-lfs-wysiwyg.html' title='django-lfs: wysiwyg и копипаст контента с других сайтов'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-5514283839006240009</id><published>2013-03-23T20:05:00.002+03:00</published><updated>2013-03-23T20:05:41.065+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bitbucket"/><category scheme="http://www.blogger.com/atom/ns#" term="jino"/><category scheme="http://www.blogger.com/atom/ns#" term="решение проблем"/><category scheme="http://www.blogger.com/atom/ns#" term="хостинги"/><title type='text'>Хостинг jino и bitbucket</title><content type='html'>Не хочу давать ни рекламы&amp;nbsp; , ни антирекламы , но у меня возникает следующая проблема с хостингом &lt;strong&gt;jino&lt;/strong&gt;.&lt;br /&gt;
Клонирование репозитория с &lt;strong&gt;bitbucket &lt;/strong&gt;в данный момент невозможно, так как hg clone отваливается по tcp-таймауту. Проблема перманентная, то есть не связана с какими-то временными трудностями на любой из сторон.&lt;br /&gt;
Вариант с клонированием через ssh не проходит, так как на jino нет ssh-клиента.&lt;br /&gt;
Вот и приходится обновлять исходники через третий сервер (&lt;br /&gt;
&lt;br /&gt;
Саппорт пока не ответил на просьбу устранить эту проблему или вообще объясить как-то причину .&lt;br /&gt;
Ждем.</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/5514283839006240009/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/03/jino-bitbucket.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5514283839006240009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5514283839006240009'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/03/jino-bitbucket.html' title='Хостинг jino и bitbucket'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-8980584459388311956</id><published>2013-03-04T18:39:00.002+03:00</published><updated>2013-03-05T17:22:13.129+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>lightbox vs elastislide</title><content type='html'>В одном из веб-проектов потребовалось реализовать галерею изображений.&lt;br /&gt;
&lt;br /&gt;
Ранее уже успешно использовал плагин jquery.elastislide.js.&lt;br /&gt;
&lt;br /&gt;
Применил и на этот раз.&lt;br /&gt;
&lt;br /&gt;
Кроме того, надо было сделать так, чтобы по клику на фотку она открывалась в &quot;полный рост&quot; - наиболее популярным решением сейчас является для этого lightbox , его я и попытался применить.&lt;br /&gt;
&lt;br /&gt;
Все сделал по манам, верстка правильная, ошибок в консоли&amp;nbsp; js нет, но изображение по клику не открывается - lightbox не фурычит.&lt;br /&gt;
&lt;br /&gt;
Сразу заподозрил конфликт обработчиков событий. Так и оказалось.&lt;br /&gt;
&lt;br /&gt;
Чтобы его преодолеть в опциях создания слайдера необходимо обнулить обработчик onClick изображений:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-js&quot;&gt;$(&#39;#carousel&#39;).elastislide({imageW :300,margin: 30,minItems: 2, &lt;b&gt;onClick: null&lt;/b&gt;});&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/8980584459388311956/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/03/lightbox-vs-elastislide.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/8980584459388311956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/8980584459388311956'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/03/lightbox-vs-elastislide.html' title='lightbox vs elastislide'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-9066100049508821129</id><published>2013-02-24T19:38:00.000+03:00</published><updated>2013-02-24T19:38:36.641+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="приложения django"/><title type='text'>Небольшая ремарка по django-imagestore</title><content type='html'>Тому, кто хочет организовать фотогалерею на django, могу посоветовать в&amp;nbsp; качестве основного приложения &lt;a href=&quot;https://github.com/hovel/imagestore&quot; target=&quot;_blank&quot;&gt;django-imagestore&lt;/a&gt; .&lt;br /&gt;
Приличный функционал, возможность расширения засчет переопределения моделей альбомов и фотографий, более-менее удобная админка.&lt;br /&gt;
Но как всегда не без греха. Как минимум одна проблема в этом модуле есть - а именно проблема каскадного удаления..&lt;br /&gt;
Допустим, у вас есть альбом, в нем много фотографий.&lt;br /&gt;
&lt;br /&gt;
Вы из админки удаляете фотографию (не выключаете из альбома, а просто удаляете).&lt;br /&gt;
Мелким шрифтом , конечно, показывается предупреждение о том, что будут удалены все сущности. Но&amp;nbsp; кто их читает ?)&lt;br /&gt;
&lt;br /&gt;
Вот и получается - хотели удалить фотку, а удалили весь альбом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
А если на альбом ссылалась еще какая-нибудь сущность, то и она успешно удалится. &lt;br /&gt;
На подобное я напарывался в &lt;a href=&quot;http://dev-after-test.blogspot.ru/2012/12/django-lfs_27.html&quot; target=&quot;_blank&quot;&gt;django-lfs&lt;/a&gt;.&lt;br /&gt;
Чтобы решить эту проблему , необходимо либо пропатчить поле Image.album, добавив в него&amp;nbsp;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #666666; display: inline !important; float: none; font-family: &#39;Trebuchet MS&#39;, Trebuchet, Verdana, sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;i style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #666666; font-family: &#39;Trebuchet MS&#39;, Trebuchet, Verdana, sans-serif; font-size: 13px; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;on_delete=models.SET_NULL.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #666666; font-family: &#39;Trebuchet MS&#39;, Trebuchet, Verdana, sans-serif; font-size: 13px; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/i&gt;Либо переопределить Image ,&amp;nbsp; как это позволяет делать imagestore и уже аналогично решить эту проблему на уровне своей модели.</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/9066100049508821129/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/django-imagestore.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/9066100049508821129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/9066100049508821129'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/django-imagestore.html' title='Небольшая ремарка по django-imagestore'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-6713812836816223218</id><published>2013-02-17T10:50:00.001+03:00</published><updated>2013-02-17T10:50:36.787+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><category scheme="http://www.blogger.com/atom/ns#" term="перепост"/><category scheme="http://www.blogger.com/atom/ns#" term="шпаргалки"/><title type='text'>Слайды: кастомизация интерфейса django-admin</title><content type='html'>На просторах интернета попалась следующая презентация, которая может задать вектор начинающему джанговоду в направлении того, как можно изменить стандартный интерфейс админки django.&lt;br /&gt;
&lt;br /&gt;
Не могу не поделиться&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;356&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; mozallowfullscreen=&quot;&quot; scrolling=&quot;no&quot; src=&quot;http://www.slideshare.net/slideshow/embed_code/1388801&quot; style=&quot;border-width: 1px 1px 0; border: 1px solid #CCC; margin-bottom: 5px;&quot; webkitallowfullscreen=&quot;&quot; width=&quot;427&quot;&gt; &lt;/iframe&gt; &lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5px;&quot;&gt;
&lt;b&gt; &lt;a href=&quot;http://www.slideshare.net/lincolnloop/customizing-the-django-admin&quot; target=&quot;_blank&quot; title=&quot;Customizing the Django Admin&quot;&gt;Customizing the Django Admin&lt;/a&gt; &lt;/b&gt; from &lt;b&gt;&lt;a href=&quot;http://www.slideshare.net/lincolnloop&quot; target=&quot;_blank&quot;&gt;Lincoln Loop&lt;/a&gt;&lt;/b&gt; &lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/6713812836816223218/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/django-admin.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/6713812836816223218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/6713812836816223218'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/django-admin.html' title='Слайды: кастомизация интерфейса django-admin'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-2030838474665663853</id><published>2013-02-12T08:57:00.000+03:00</published><updated>2013-02-13T09:05:19.783+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="perl"/><category scheme="http://www.blogger.com/atom/ns#" term="tips&#39;n tricks"/><title type='text'>How to improve Test::Class to conrol test ttl</title><content type='html'>To&amp;nbsp; make Test::Class control test-suites time-to-live you could inherit Test::Class and redefine runtests method..&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;sh_perl sh_sourceCode&quot; style=&quot;background-color: #eeeeee; border: 1px solid rgb(136, 136, 136); color: black; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; padding: 1em; text-indent: 0px; text-transform: none; white-space: pre; widows: 2; word-spacing: 0px;&quot;&gt;&lt;code&gt;package TTL::Test::Class;
use base qw(Test::Class);
use Test::More;
use POSIX &quot;:sys_wait_h&quot;;
use constant DEFAULT_TIMEOUT =&amp;gt; 60;
# переопределяем метод запуска тестов 
sub runtests{
    my $t = DEFAULT_TIMEOUT;                                           
    my $pid = fork;                         
    my $child_ret_code;                           
    if( $pid &amp;gt; 0 ){ # parent process                                         
       #child waiting loop
       my $ok_flag = 0;                                                  
       for(my $i=0; $i &amp;lt; $t; $i++){                                       
          if(waitpid($pid, WNOHANG)){                                           
               $child_ret_code = $?/256;                                       
               ok($child_ret_code);                                             
               $ok_flag = 1;                                                  
               last;                                                            
          };                                                                              
          sleep(1);
       };
       if( not $ok_flag ){
         diag &quot;Killing test by its timetolive...&quot;;
         kill TERM =&amp;amp;gt; 
         $pid;
         return $ok_flag;
       };
       return $child_ret_code;                                                  
    } elsif( $pid == 0 ) { #child                                               
        exit $self-&amp;gt;SUPER::runtests;                                         
    } elsif ( not defined($pid) ) { #unsuccessfull fork                         
        die &quot;Cannot fork child process: $!&quot;;                                    
   }                                                                            
} 
1;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
I think, we don&#39;t need SIGCHILD here..&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://qaimprove.blogspot.ru/2013/02/testclass.html&quot; target=&quot;_blank&quot;&gt;source&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/2030838474665663853/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/how-to-improve-testclass-to-conrol-test.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/2030838474665663853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/2030838474665663853'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/how-to-improve-testclass-to-conrol-test.html' title='How to improve Test::Class to conrol test ttl'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-9111093333933773595</id><published>2013-02-05T09:26:00.001+03:00</published><updated>2013-02-11T10:31:40.640+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="шпаргалки"/><title type='text'>django-sitetree: key error &#39;request&#39;</title><content type='html'>Сообщение об ошибке при работе с django-sitetree&amp;nbsp; в админке django :&lt;br /&gt;
&lt;br /&gt;
говорит о том , что необходимо добавить&lt;br /&gt;
&lt;br /&gt;
&lt;h1&gt;
KeyError at /admin/sitetree/tree/1/&lt;/h1&gt;
&lt;pre class=&quot;exception_value&quot;&gt;&#39;request&#39;&lt;/pre&gt;
&lt;table class=&quot;meta&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;
      &lt;th&gt;Request Method:&lt;/th&gt;
      &lt;td&gt;GET&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;th&gt;Request URL:&lt;/th&gt;
      &lt;td&gt;http://localhost:8080/admin/sitetree/tree/1/&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;th&gt;Django Version:&lt;/th&gt;
      &lt;td&gt;1.4.3&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;th&gt;Exception Type:&lt;/th&gt;
      &lt;td&gt;KeyError&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;th&gt;Exception Value:&lt;/th&gt;
      &lt;td&gt;&lt;pre&gt;&#39;request&#39;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&quot;django.core.context_processors.request&quot;, в TEMPLATE_CONTEXT_PROCESSORS&lt;br /&gt;
&lt;br /&gt;
только&amp;nbsp; и всего </content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/9111093333933773595/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/django-sitetree-key-error-request.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/9111093333933773595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/9111093333933773595'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/02/django-sitetree-key-error-request.html' title='django-sitetree: key error &#39;request&#39;'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-7374885813982585295</id><published>2013-01-31T18:15:00.000+03:00</published><updated>2013-01-31T18:15:25.495+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="django-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="ошибки"/><title type='text'>django-lfs: EOFError при работе в режиме кеширования</title><content type='html'>На одном моем сервере &quot;крутится&quot; магазинчик под управлением &lt;b&gt;Django-lfs&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;django 1.4&lt;/li&gt;
&lt;li&gt;nginx 1.1.9&lt;/li&gt;
&lt;li&gt;uwsgi 1.2.3&lt;/li&gt;
&lt;/ul&gt;
Время от времени на тревожный email приходят сообщения об ошибке вида:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;EOFError&lt;/span&gt;&lt;br /&gt;
&lt;br style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot; /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;TRACEBACK:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; File &quot;..../&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;pydocs/env/lib/python2.7/site-&lt;/span&gt;&lt;br /&gt;
&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;packages/Django-1.4.1-py2.7.&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;egg/django/core/handlers/base.&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;py&quot;, line 111, in get_response&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; response = callback(request, *callback_args, **callback_kwargs)&lt;/span&gt;&lt;br /&gt;
&lt;br style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot; /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; File &quot;..../&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;pydocs/deploy/../lfs/catalog/&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;views.py&quot;, line 267, in category_view&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; inline = category_products(request, slug, start)&lt;/span&gt;&lt;br /&gt;
&lt;br style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot; /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; File &quot;...../&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;pydocs/deploy/../lfs/catalog/&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;views.py&quot;, line 358, in category_products&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; temp = cache.get(cache_key)&lt;/span&gt;&lt;br /&gt;
&lt;br style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot; /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; File &quot;....../&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;pydocs/env/lib/python2.7/site-&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;packages/Django-1.4.1-py2.7.&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;egg/django/core/cache/&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;backends/db.py&quot;, line 75, in get&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; return pickle.loads(base64.&lt;/span&gt;&lt;wbr style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;&lt;/wbr&gt;&lt;span style=&quot;-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: white; color: #500050; display: inline !important; float: none; font-family: arial, sans-serif; font-size: 13.333333969116211px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;decodestring(value))&lt;/span&gt; &lt;br /&gt;
&lt;br /&gt;
Ошибка &quot;мигающая&quot;.&lt;br /&gt;
&lt;br /&gt;
Пока лишь понятно, что копать в сторону python модуля pickle .&lt;br /&gt;
&lt;br /&gt;
Поверхностный анализ кода этого pickle пока не помог в поиске причины.&lt;br /&gt;
&lt;br /&gt;
Ждет меня дебаг продолжительный, судя по всему :)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/7374885813982585295/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2013/01/django-lfs-eoferror.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/7374885813982585295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/7374885813982585295'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2013/01/django-lfs-eoferror.html' title='django-lfs: EOFError при работе в режиме кеширования'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-111205258811610203</id><published>2012-12-27T21:59:00.000+03:00</published><updated>2012-12-27T21:59:02.337+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="djang-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="ORM"/><category scheme="http://www.blogger.com/atom/ns#" term="ошибки"/><title type='text'>django-lfs: грабли с каскадным удалением</title><content type='html'>Текущая известная мне версия django-lfs писалась для django версий еще младших, чем 1.3. До этой версии включительно ORM этого фреймворка содержал досадную &quot;особенность&quot; &amp;nbsp;- ненастраиваемое каскадное удаление сущностей , ссылающихся на удаляемый объект.&lt;div&gt;
Кто не знал этой особенности, получал граблями по лбу либо при тестировании, либо уже, что тоже бывало , при &amp;nbsp;эксплуатации.&lt;/div&gt;
&lt;div&gt;
Классический фейл с django-lfs: оператор интернет магазина решает удалить производителя, ставшего ненужным. На этот момент к производителю были привязаны пара сотен товаров.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Manage-интерфейс lfs настолько дружелюбен, что не предупреждает юзера об удалении этих пары сотен товаров, заодно с удалением производителя. Но ведь так можно и до инфаркта людей довести! ) В общем эдакое&amp;nbsp;&amp;nbsp;&lt;strike&gt;&quot;кто не спрятался &amp;nbsp;я не виноват&quot;&lt;/strike&gt;&amp;nbsp; кто не делает бекап, вбивает все заново))&lt;/div&gt;
&lt;div&gt;
Более опытные django-воды обходили подобные проблемы либо на уровне БД либо в хуке для delete-операции, явно обнуляя соответствующие поля в ссылающихся таблицах.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Начиная с версии 1.3 появилась возможность настраивать ORM при удалении объекта. Для этого в описании поля модели надо указывать:&amp;nbsp;&lt;i&gt;on_delete=models.SET_NULL&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Круто, только вот разрабы lfs об этом не позаботились, так что патчить модели надо самим.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Ну и в завершение.. чтобы избегать подобных граблей:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
1. не надейтесь на протестированность сторонних решений, особенно , если они бесплатные&lt;/div&gt;
&lt;div&gt;
2. постоянно углубляйте знания инструментария, которым пользуетесь .. в данном случае курить djangoproject.com&lt;/div&gt;
&lt;div&gt;
3. ежедневный бекап БД спасет от большинства подобных фейлов ( а лучше бекапиться несколько раз в день )&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/111205258811610203/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2012/12/django-lfs_27.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/111205258811610203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/111205258811610203'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2012/12/django-lfs_27.html' title='django-lfs: грабли с каскадным удалением'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-4102777564294791636</id><published>2012-12-16T18:56:00.000+03:00</published><updated>2013-05-23T08:29:59.714+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="django-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>django-lfs: улучшение механизма работы с картинками</title><content type='html'>В предыдущем посте я упоминал об ошибке, которая возникнет , если пользователь сайта на django-lfs будет загружать картинки с именем файла , длиной более 99 символов.&lt;br /&gt;
&lt;br /&gt;
Пользователей не выбирают, а костыли в виде явного указания немеряного max_length , меня не устраивают.&lt;br /&gt;
&lt;br /&gt;
Я решил сделать так:&lt;br /&gt;
&lt;br /&gt;
1. принимаем картинку&lt;br /&gt;
2. запоминаем расширение файла&lt;br /&gt;
3. получаем хеш (например md5) от имени&amp;nbsp; + текущее время (чтобы не получать одинаковых хешей для разных картинок с одинаковыми именами)&lt;br /&gt;
4. получаем новое имя конкатенацией хеша и расширения&lt;br /&gt;
5. сохраняем&lt;br /&gt;
&lt;br /&gt;
Наилучшим местом в коде, куда вклинить этот алгоритм является lfs/core/fields/thumbs.py&lt;br /&gt;
&lt;br /&gt;
Подключаем вспомогательные библиотеки:

&lt;br /&gt;
&lt;div style=&quot;background-color: #dddddd; border-radius: 6px; border: 1px solid #888; padding: 10px;&quot;&gt;
&lt;code&gt;


+++ b/pydocs/lfs/core/fields/thumbs.py  Sun Dec 16 19:17:04 2012 +0400
@@ -7,6 +7,13 @@&lt;br /&gt;
 except ImportError:&lt;br /&gt;
     from PIL import Image&lt;br /&gt;
&lt;br /&gt;
+try:&lt;br /&gt;
+    from hashlib import md5&lt;br /&gt;
+except ImportError:&lt;br /&gt;
+    from md5 import md5&lt;br /&gt;
+from time import time&lt;br /&gt;
&lt;br /&gt;
&lt;/code&gt;
&lt;/div&gt;
Генерируем новое имя файла перед сохранением:
&lt;br /&gt;
&lt;div style=&quot;background-color: #dddddd; border-radius: 6px; border: 1px solid #888; padding: 10px;&quot;&gt;
&lt;code&gt;
     def save(self, name, content, save=True):&lt;br /&gt;
+       parts = name.split(&#39;.&#39;)&lt;br /&gt;
+       ext = &#39;.%s&#39; % parts[-1] if len(parts) &amp;gt; 1 else &#39;&#39;&lt;br /&gt;
+       name = md5(&quot;%s-%s&quot;%(name.encode(&#39;utf-8&#39;), time())).hexdigest()&lt;br /&gt;
+       name = &quot;%s%s&quot;%(name,ext)&lt;br /&gt;
        super(ImageWithThumbsFieldFile, self).save(name, content, save)&lt;br /&gt;
&lt;/code&gt;
&lt;/div&gt;
После этого все имена картинок будут одинаковой длины и о том  , зачем юзеру такие длинные файлы, можно не думать.

p.s. дальнейшее улучшение механизма работы с картинками будет - проверка файла на то, в допустимом графическом ли он формате или нет.
Сейчас django-lfs принимает на вход все подряд. Судя по всему, безопасности это практически не угрожает , но 404 по запросам картинок - это тоже нехорошо.



</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/4102777564294791636/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2012/12/django-lfs_16.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/4102777564294791636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/4102777564294791636'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2012/12/django-lfs_16.html' title='django-lfs: улучшение механизма работы с картинками'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-618236974937224190.post-5084916615895262734</id><published>2012-12-16T13:34:00.003+03:00</published><updated>2012-12-16T13:57:15.328+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="djang-lfs"/><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="ошибки"/><title type='text'>django-lfs: пара тройка неприятных багов</title><content type='html'>Хочу рассказать о нескольких неприятных моментах (читай &quot;ошибках&quot;), с которыми совсем недавно столкнулся при использовании&lt;b&gt; django-lfs&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Ошибки при сохранении картинок с длинными именами&lt;/h4&gt;
Для хранения картинок в django-lfs используется специальный тип поля, пронаследованный от стандартного ImageFile. В этом стандартном типе дефолтная длина файла картинки 100 символов.&lt;br /&gt;
В модели , которая используется для хранения картинок товаров , например, max_length явно не указывается. В итоге при попытке отобразить превьюхи (thumbs) оригинальной картинки с длинным именем ( &amp;gt;= 100 символов), случается поначалу непонятный IndexOutOfRange..Казалось бы причем тут массивы...&lt;br /&gt;
&lt;br /&gt;
Вот такой замечательный код есть..&lt;br /&gt;
&lt;div style=&quot;background-color: #cccccc; border-radius: 6px; border: 1px solid #555;&quot;&gt;
&lt;code&gt;
&lt;br /&gt;
class ImageWithThumbsFieldFile(ImageFieldFile):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;&quot;&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; See ImageWithThumbsField for usage example&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;&quot;&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def __init__(self, *args, **kwargs):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; super(ImageWithThumbsFieldFile, self).__init__(*args, **kwargs)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.sizes = self.field.sizes&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if self.sizes:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; def get_size(self, size):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if not self:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &#39;&#39;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; split = self.url.rsplit(&#39;.&#39;, 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumb_url = &#39;%s.%sx%s.%s&#39; % (split[0], w, h, split[1])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return thumb_url&lt;br /&gt;
&lt;br /&gt;
&lt;/code&gt;
&lt;/div&gt;
падает, как нетрудно догадаться,&amp;nbsp; в строчке&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: #cccccc; border-radius: 6px; border: 1px solid #555;&quot;&gt;
&lt;code&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumb_url = &#39;%s.%sx%s.%s&#39; % (split[0], w, h, split[1])&lt;br /&gt;
&lt;br /&gt;
&lt;/code&gt;&lt;/div&gt;
Причина в том, чтo в rsplit передается усеченное имя файла.. Как видим, никакими дополнительными проверками авторы себя не обременили, поэтому дело и доходит до &quot;пятисоток&quot;..&lt;br /&gt;
&lt;br /&gt;
Запретить пользователям не аплоадить такие картинки - нельзя.&lt;br /&gt;
&lt;br /&gt;
Планирую следующий фикс: все картинки, поступающие в django-lfs сохранять под сгенерированными уникальными именами заранее фиксированной длины.&lt;br /&gt;
&lt;br /&gt;
А пока для своих проектов на django-lfs сделал небольшой костыль в виде max_length = 2048 в описании модели картинки.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Глюки с редактированием товаров в manage-интерфейсе&lt;/h4&gt;
&lt;b&gt;django-lfs&lt;/b&gt; позиционируется как шустрый фреймворк для ешопов. Шустрость его в частности основана на активном использовании кеширования бд.&lt;br /&gt;
&lt;br /&gt;
Баг , который я сейчас опишу, как раз&amp;nbsp; и проявляется при использовании кеширования.&lt;br /&gt;
&lt;br /&gt;
Допустим , вы используете кеширование в таблице БД. Выставляете время жизни объектов в кеше , например , в 60 секунд.&lt;br /&gt;
&lt;br /&gt;
Пользователь магазина наконец-то решает заняться наполнением. Создает товар, редактирует &quot;данные&quot; и сохраняет их . Затем переходит на &quot;категории&quot; и вносит товар в нужные категории. &quot;Сохранить категории&quot;. Лезет на сайт, а товара там нет... Лезет в интерфейс управления и видит, что &quot;активно&quot; , не выставлен, цены нет и вообще вкладка &quot;данные&quot; такая, как будто он к ней не прикасался.&lt;br /&gt;
Причина в том, что между сохранением &quot;данных&quot; и&amp;nbsp; сохранением&amp;nbsp; &quot;категорий&quot; не прошло минуты и при сохранении&amp;nbsp; категорий, товар взялся из кеша.&lt;br /&gt;
&lt;br /&gt;
Вопрос, почему не был обновлен кеш при сохранении &quot;данных&quot; , пока открыт. Выясню и исправлю, ведь без кеширования как-то несолидно :)&lt;br /&gt;
&lt;br /&gt;
Да и есть такие django-модули, которые без&lt;br /&gt;
&amp;nbsp;кеширования&amp;nbsp; вообще не работают. Например, используемый многими &lt;b&gt;supercaptcha&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;UPD:&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
Глюк с редактированием товаров исправляется отправкой сигнала product_changed в products.py (после сохранения формы данных),&amp;nbsp; а также с отправкой аналогичного сигнала при изменении категорий товара.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-after-test.blogspot.com/feeds/5084916615895262734/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dev-after-test.blogspot.com/2012/12/django-lfs.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5084916615895262734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/618236974937224190/posts/default/5084916615895262734'/><link rel='alternate' type='text/html' href='http://dev-after-test.blogspot.com/2012/12/django-lfs.html' title='django-lfs: пара тройка неприятных багов'/><author><name>will</name><uri>http://www.blogger.com/profile/02812813329963523314</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYd-NeXqJyut7D7vDuxm8dDt9LmJUBE8LSckLSkN0P4LJAxwARK8Zc5HFN37iFi8l5Yk6YKgAJtdNwRuyADtVIV6gqnxGolZsb1zmBUk8CKdQM3pF-48TSF-AME9lkkQ/s220/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png'/></author><thr:total>4</thr:total></entry></feed>