четверг, 25 октября 2012 г.

Ненавижу виртуальные хостинги

Виртуальные хостинги (shared hosting) в моем понимании - зло. Все эти jail, ограничения, квоты, "шаг влево , шаг вправо" доводят до седых волос, когда в очередной раз  надо развернуть проект, который вот только что "успешно работал на тестовом сервере"...

Как только зальешь на вирт.хостинг, сразу начинаются проблемы и проблемки. И как внимательно не читай отзывы и описания тарифных планов, как тщательно не выспрашивай все у саппорта - ты обязательно наткнешься как какое-нибудь г.... Например в таком виде: на хостинге криво установлен python-mysql - ну не хочет проект запускаться . Требуется явный апгрейд библиотеки, установка -dev версии , возможно самостоятельная ручная сборка... Но бдительный хостер забанил все и вся - пользуйся тем, что есть  как хочешь.

Пишешь саппорту слезную жалобу "ну установите мне то или то"... и хорошо ,если ответят через день... Бывает неделями не отвечают....

Ну и как быть?

В топку дорогие и дешевые shared hosting с их "удобными панелями".. берем vps , и делаем с ней все, что душе угодно - с умом , конечно :) И тогда решение любой (ну или совсем почти любой) технической проблемы оказывается в наших собственных руках!

вторник, 23 октября 2012 г.

Решение проблемы с PIL на хостинге Джино (Jino)

Сегодня потребовалось перенести один из django-проектов на свежеорганизоавнный хостинг "Джино".
Предварительное знакомство с опциями тарифного плана оставило хорошее впечатление - здесь вам и virtualenv и ssh .
Файлы проекта были перенесены успешно, wsgi-скрипт был настроен также за минуту согласно рекомендациям хостера. Чуть подольше ставил нужные либы в виртуальное окружение.
Сайт оказался работоспособным удивительно быстро.
Но первая и пока последняя трудность возникла почти сразу - тестовая загрузка картинки закончилась неудачно.
Немного дебага показало "INFO decoder jpeg not available".
Сразу стало все ясно - PIL в виртуальном окружении установился криво - а точнее без поддержки libjpeg (и не только ее ). Пляски с переменными окружения и указыванием путей к libjpeg не помогли.. И неудивительно , libjpeg-dev на сервере не оказалось.
Ситуацию спасла предустановленная PIL , которая оказалась на сервере - подкладываем ее в virtualenv и все работает )

суббота, 20 октября 2012 г.

sqlite - не поддерживается изменение колонок

Многие , кто только начинает использовать sqlite в работе, часто натыкаются на то, что не могут провести привычную для других СУБД операцию изменений параметров колонки.
Например, у поля в данный момент ограничение NOT NULL, которое вам мешает и вы хотите пометить ее как NULL.
Пробуете применить ALTER TABLE и ... облом.
Перепроверять синтаксис запроса - бесполезно :) sqlite (по-крайней мере текущая 3-я версия ) эту операцию попросту не поддерживает.
Выход один: пересоздать таблицу. Ну а чтобы не потерять данные, предварительно копируете их в резервную таблицу:

  create table tms as select * from table_to_backup; 

после пересоздания возвращаете данные на место

  insert into new_Table_version select * from table_to_backup;

django-lfs: ошибка при управлении остатками

Если при добавлении в корзину товара вы натолкнулись на следующее сообщение об ошибке


TypeError at /product-form-dispatcher

unsupported operand type(s) for /: 'float' and 'NoneType'
Request Method:POST
Request URL:http://test/product-form-dispatcher
Django Version:1.4.1
Exception Type:TypeError
Exception Value:
unsupported operand type(s) for /: 'float' and 'NoneType'
Exception Location:/home/projects/eshop/pydocs/deploy/../lfs/catalog/models.py in get_amount_by_packages, line 780
Python Executable:/usr/sbin/uwsgi
то скорее всего дело в том, что для данного товара вы не указали packing_unit . Этот параметр необязателен, и такое поведение - несомненный баг. Открываем catalog/models.py и правим багу в функции get_amount_of_packages:


780,781c780,781 
< packages = math.ceil(quantity / pu) 
< return packages * pu 
--- 
> packages = math.ceil(quantity / self.packing_unit) 
> return packages * self.packing_unit

вторник, 9 октября 2012 г.

jquery: выравниваем высоту элементов

Наверняка, многие сталкивались подобной ситуацией:

Есть футер, в нем несколько горизонтально располагающихся друг за другом блоков..
Например блоки быстрых ссылок.
У этих блоков свой фон, который отличается от основного фона.
Содержимое блоков (читай, высота) заранее неизвестны.

В результате блоки получаются разной высоты, что может смотреться некрасиво.

Кто-то пытается решить проблему подбором min-height побольше, что лишь снижает вероятность возникновения проблемы, но не решает ее.

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

Кто-то использует старые добрые таблицы )

Я же использую незатейливый js-код и ставшую уже классикой - jquery

Например ,  у описанных блоков класс footer-block. Сделать их равной высоты можно примерно так:


        <script>
          var maxh=0;
          $('.footer-block').each(
            function(){
              var h = $(this).height();
              if( h  > maxh){
                maxh = h;
              }
            }
          );
          $('.footer-container').css('height',maxh);
        </script>


django:использование MultipleChoiceField в моделях

Сегодня натолкнулся на проблему... В django foms есть замечательное поле MultipleChoiceField. Позволяет, как не трудно догадаться, показывать пользователю контрол с возможностью множественного выбора.
Описывается , например, так (в классе формы):

EQUIPMENT_VARIANTS = ( 
 ('pm',u'Посудомоечная машина'),
 ('sm',u'Стиральная машина'),
 ('vr',u'Варка'),
 ('du',u'Духовка'),
 ('mi',u'Микроволновка'),
 ('ho',u'Холодильник'),
 ('vy',u'Вытяжка'), 


equipment = forms.MultipleChoiceField(choices=EQUIPMENT_VARIANTS, required=False)   

Все хорошо - форма рисуется, данные принимаются. Надо сохранить в БД.

Обнаруживается, что для Models поля-аналога нет.

Нормализовать БД, создавая новую словарную таблицу, не планирую и не хочу.

Хочу просто хранить список строк в одном поле.

Что ж, в соответствующей модели объявляем такое поле:

 equipment = models.CharField( max_length="1024", null=True, blank=True)

Привязываем форму к модели , используя forms.ModelForm.
Теперь данные сохраняются в БД. Но есть проблема. В БД они в таком виде: "[u'pm', u'sm']"

Когда все это затеивал знал, что для ChoiceField (вернее для CharField с аттрибутом choices) есть замечательная функция-хелпер get_FOO_display.

Замечательна она тем, что позволяет в шаблоне без лишних движений получить значение выбранной опции , а не мнемонику. Это нужно , например, при выводе превью формы или результата ее сабмита или вообще при выводе значения поля таблицы, которое описано с атрибутом choices.

Наивно полагал, что и для множественного выбора удастся в недрах django раскопать что-то подобное... Но увы. гуглеж выдал несколько решений с самопальными сниппетами и фильтрами. Не понравилось.

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

#не забыть import re 

def get_equipment_list(self): 
    p = re.compile('\'(\w+)\'') 
    result = [] 
    for e in p.findall(self.equipment): 
       for v in EQUIPMENT_VARIANTS: 
          if v[0] == e: 
             result.append(v[1]) 
    return result 

Функция получает список мнемоник значения поля equipment и формирует список значений опций из EQUIPMENT_VARIANTS - этот массив опций пришлось сделать видимым не только в классе формы , но и в классе модели.

Теперь в django-шаблоне можно спокойно получить для объекта результат множественного выбора из одного из его полей (в данном случае equipment).

Ну а дальше отрисовать этот список как угодно.

Надеюсь, кому-то сэкономит время.