• Прием смс

    Рассылать смс сегодня нетрудно — регистрируемся в одном из многочисленных сервисах рассылок, вносим сумму и вперед. А как принимать смс от граждан в автоматическом режиме?

    Короткие номера не подходит, ибо они навек закрепили за собой репутацию лохотрона. К тому же нужно вводить префикс, а минимальная стоимость 4 рубля. Принимать только на короткие номера — верх свинства по отношению к абонентам.

    А ведь все можно сделать своими руками! Берем простой 3Г-модем, втыкаем в него местную симку (я взял Мегафон), подключаем к компьютеру, ставим драйвера. Проверяем, появился ли в системе модем.

    Качаем замечательную утилиту Гамму, а конкретно — виндовые бинарники (не Minimal, а обычные). Распаковываем.

    Утилита gammu может рулить модемом программно, например, читать и отправлять смс, совершать звонки, делать бекапы содержимого телефона и массу других полезных штук. В комплекте идет gammu-smsd — демон для чтения смс в фоновом режиме. Он постоянно проверяет наличие смс, складывает их в базу данных и вызывает заданную команду в момент прихода новой смски.

    Теперь о том, как все настроить. В папке bin создаем файл smsdrc следующего содержания:

    [gammu]
    device = COM6:
    connection = at
    
    [smsd]
    Service = sql
    Driver = native_mysql
    User = user
    Password = password
    PC = xxx.xxx.xxx.xxx
    Database = smsd
    PIN = 8730
    LogFile = smsd.log
    RunOnReceive = smsd_callback.bat
    

    Стартуем демона:

    gammu-smsd --config smsdrc
    

    Секция [gammu] в конфигурации отвечает за параметры соединения с устройством. device — номер КОМ-порта, узнать его можно в свойствах модема, connection — тип соединения, для 3Г-модема обычно at.

    Раздел [smsd] содержит параметры демона. Как видно, в качестве базы я использую Мускуль. Опция PIN задает пин-код симки (если защита ПИН не отключена). LogFile — текстовый файл логов.

    Самое интересное — RunOnReceive, это имя команды, скрипта или батника, который будет вызываться при получении смс. Параметры сообщения передаются в переменных окружения SMS_1_NUMBER, SMS_1_TEXT и др.

    В батнике у меня прописан вызов питоньего скрипта:

    start pythonw path\to\smsd_callback.py
    

    Почему бы сразу не вызвать скрипт? Потому, что вызов осуществляется в том же потоке, что и чтение смс, поэтому пока не завершится процесс команды, чтение будет приостановлено. А в данном случае батник вызывает скрипт и сразу закрывается.

    Фрагмент кода на питоне:

    number = os.environ["SMS_1_NUMBER"]
    message = os.environ["SMS_1_TEXT"]
    
    msg_pattern = r"\d+"
    account, value = re.findall(msg_pattern, message)[:2]
    
    statement = Statement(account=account, value=value)
    statement.save()
    
    answer = u"Принято. Абонент %s, показание %s" % (account, value)
    
    send_sms(answer, number)
    

    Получаем номер и сообщение, находим в нем пару чисел — лицевой счет и показание прибора. Сохраняем в базу и отвечаем абоненту, что все в порядке.

    Комментарии из старого блога

    11/04/13 Сергей: Статья интерсная, много нового узнал, пытаясь запустить. Но нет ничего про структуру базы. Мануалов гаммы на русском нет. Вот и как бы статья по прямому предназначению “Прием смс” (профи и без статьи организует) пока не очень полезна.

    11/05/13 Иван Гришаев: Структуру базы можно посмотреть в .sql-файле, который лежит где-то в папке с программой.

    11/07/13 Сергей: Спасибо. Теперь вот такая картина в логфайле (тут я баран)) поможете??? подключаю 3g модем - железка от алкател.

    Thu 2013/11/07 15:09:29 gammu-smsd[2452]: Connected to Database: smsd on localhost
    Thu 2013/11/07 15:09:29 gammu-smsd[2452]: Connected to Database native_mysql: smsd on localhost
    Thu 2013/11/07 15:09:29 gammu-smsd[2452]: Created Windows RW shared memory at 003A0000
    Thu 2013/11/07 15:09:29 gammu-smsd[2452]: Starting phone communication...
    Thu 2013/11/07 15:09:40 gammu-smsd[2452]: Error at init connection: No response in specified timeout. Probably phone not connected. (TIMEOUT[14])
    Thu 2013/11/07 15:09:40 gammu-smsd[2452]: Already hit 250 errors
    Thu 2013/11/07 15:09:40 gammu-smsd[2452]: Terminating communication: No response in specified timeout. Probably phone not connected. (TIMEOUT[14])
    Thu 2013/11/07 15:09:40 gammu-smsd[2452]: Starting phone communication...
    Thu 2013/11/07 15:09:50 gammu-smsd[2452]: Error at init connection: No response in specified timeout. Probably phone not connected. (TIMEOUT[14])
    Thu 2013/11/07 15:09:50 gammu-smsd[2452]: Already hit 250 errors
    Thu 2013/11/07 15:09:50 gammu-smsd[2452]: Terminating communication: No response in specified timeout. Probably phone not connected. (TIMEOUT[14])
    Thu 2013/11/07 15:09:50 gammu-smsd[2452]: Starting phone communication...
    

    11/07/13 Иван Гришаев: Пишет, что нет соединения с телефоном. Сначала нужно указать проге, какой порт слушать. Создайте файл Gammu\bin\gammurc (без расширения), в нем пишете:

    [gammu]
    device = COM6:
    connection = at
    

    только вместо COM6 - ваш порт. Двоеточие на конце нужно.

    11/07/13 Сергей: Я так и делал, модем откликается (в терминале) на сом3,4,5 в диспетчере оборудования модем=сом5.

    [gammu]
    device = COM
    

    пробовал все результат почти один, 3 и 5 сукунд через 10 закрывается гамми, ком4 каждые 10-20 сек перепроверяет соединение с телефоном, пока сам не закрою.

    11/07/13 Иван Гришаев: Вспомнил - для смс-демона нужен отдельный конфиг! Gammu\bin\smsdrc

    У меня он такой:

    [gammu]
    device = COM5:
    connection = at
    
    [smsd]
    Service = sql
    Driver = native_mysql
    User = username
    Password = passowrd
    PC = 172.27.86.8
    Database = smsd
    
    LogFile = smsd.log
    RunOnReceive = some_bat_file.bat
    CheckSecurity = 0
    CheckBattery = 0
    

    11/07/13 Сергей: Не помогло добавление Check ов. Нарыл гдето другой терминал, вот он АТ командами смски вытягивает. А можно както на питоне опросить АТ командами com порт? Думаю так проще будет.

    11/07/13 Иван Гришаев: Конечно можно, есть либа для ком-порта: http://pyserial.sourceforge.net/

    Кстати, вы пробовали http://www.simplesms.ru/ ? Прога очень хорошая, разработчик - русский, есть документация и форум.

    11/07/13 Сергей: Хороший вы (я не против и на ты) человек. С библиотекой буду разбираться (инглиша не знаю), а платные вещи отпадают я имено хочу разобраться и сделать - типа хобби). Можно вообще не париться - 800р/мес и прикрутить их API к своему сервису, я так и делал, но как то не уютно))).

    11/07/13 Сергей: надо же скрипт php заработал, раньше порты были 14,15,16 и не работало. Попробую на php получалку сделать!

    $telnumb='904*****37';
    $sms_text='poluchilos';
    $format = "AT+CMGF=1\r\n";
            $tel = "at+cmgs=\"+7".$telnumb."\"\r\n ";
            $text = $sms_text.chr(26)."\r\n ";
            $fp = fopen ("COM3:", "w");
            flock($fp,LOCK_EX);
            if(!$fp){
                    echo "COM-Port not opened";
            }
            else{
                    fwrite($fp, $format);
                                    sleep(1);
                    fwrite($fp, $tel);
                                    sleep(1);
                    fwrite($fp, $text);
                                    sleep(1);
                    flock($fp,LOCK_UN);
                    echo $format.$tel.$text;
            }
            $fp = fclose ($fp);
    

    11/07/13 Иван Гришаев: Сообщения с кириллицей нормально приходят? А сообщения из нескольких частей?

    11/07/13 Сергей: Нет под w1251 все усложняется, там меняется алгоритм сборки, но это решаемо. Мне прием нужен, его и ковыряю. На php отправить оказывается просто, а вот принять “одна темнота” пока, т.что гамми, питон не закрываю.

    11/07/13 Сергей: Так то все дожно быть просто. Всего то нужно в порт заслать "AT+CMGL=4\r\n" и получить все что он отдаст. А потом раскодить, распарсить. Ну нннникак.

    11/08/13 Иван Гришаев: Да, кириллица хранится в последовательностях UFT-16, кажется. Придется декодировать.

    11/07/13 Сергей: Еще об отправке, там без подтверждения получения смс абонентом и по той же причине - читать порт не получается.

    11/07/13 Сергей: simplesms пробовал скачать - антивирус заблокировал(((

    11/08/13 Иван Гришаев: А вы разблокируйте.

  • 1С и JSON в продакшене

    Еще раз обновил функцию перевода структур 1С в JSON: http://pastebin.com/3NwCDCTD

    Исправлены косяки:

    • нулевые числа форматируются корректно;
    • в строках корректно обрабатываются управляющие символы (\n, \t и др);
    • символы Юникода не переводятся в последовательности вида \uxxxx, потому что это долго (хотя позволяет избежать проблем с кодировкой).

    Уже использую функцию для взаимодействия с клиентской частью на Питоне, полет нормальный.

    Комментарии из старого блога

    12/25/12 Alex: На вскидку Вы забыли про разделитель триад в числах. И я советовал бы XMLЗначение (пишу по памяти) вместо Формат - и быстрее и меньше ошибок будет.

    12/25/12 Иван Гришаев: Разделитель убран:

    ИначеЕсли Тип = Тип("Число") Тогда
                    Возврат Формат(Объект, "ЧРД=.; ЧН=0; ЧГ=0");
    

    ЧГ=0 убирает разделитель разрядов. Он же не нужен.

    Вы имели в виду XMLСтрока(). Можно и так, но, во-первых, исчезает ясность (что получается на выходе), а во-вторых, в некоторых случаях он не подходит, например, Неопределено преобразуется в пустую строку, а нужно в null. И не все типы данных поддерживаются.

  • Автоматическая выгрузка вложений

    Getmail — потрясающая утилитка, сэкономившая мне массу времени и нервов. Она сохраняет электронные письма на диск, попутно распаковывая вложения.

    Сказать, что это удобно, значит, ничего не сказать. Ведь, казалось бы, простую задачу — обеспечить автоматическую выгрузку вложений из писем — почтовые клиенты выполнить не в состоянии без установки плагинов и костылей. А с помощью getmail проблема решается несколькими строками в батнике:

    d:
    cd \.attachments
    getmail -u user@server.ru -pw "password" -s server.ru -xtract -delete
    del MSG*.TXT
    del Extract*.out
    

    Указываем, папку, выгружаем, чистим всякий мусор, далее работаем с аттачами.

  • 1С и JSON: работа над ошибками

    UPD: новая версия

    Пилотная версия функции преобразования данных 1С в JSON оказалась вполне удачной. Делюсь новой версией: http://pastebin.com/y2K5V3Xt

    Исправления:

    • типы Неопределено и Null преобразуются в null;
    • добавлен тип СписокЗначений;
    • исправлен ISO-формат даты;
    • строки преобразовываются в последовательности вида \uxxxx.

    Напомню, что код состоит из одной функции и не зависит от сторонних модулей и компонент.

    Пример:

    с = новый СписокЗначений;
    с.Добавить("Привет!");
    с.Добавить(42);
    с.Добавить(ТекущаяДата());
    с.Добавить(Неопределено);
    с.Добавить(Null);
    с.Добавить("!№2№%Ё~{}");
    с.Добавить(новый Структура("поле1, поле2", ВидДвиженияБухгалтерии.Дебет, новый Массив(3)));
    Сообщить(json(с));
    

    Результат:

    [
      "\u041f\u0440\u0438\u0432\u0435\u0442!",
      42,
      "2012-11-13T10:17:55",
      null,
      null,
      "!\u21162\u2116%\u0401~{}",
      {
        "\u043f\u043e\u043b\u04352": [
          null,
          null,
          null
        ],
        "\u043f\u043e\u043b\u04351": "\u0414\u0435\u0431\u0435\u0442"
      }
    ]
    

    Комментарии из старого блога

    11/21/12 Артемий Зайцев: А зачем все символы заменять на подстановки \u0414 ? Вместо “N” (1 байт) получим замену в 6 байт при передаче по интернету. Вся прелесть JSON теряется. XML становится выгоднее.

    11/21/12 Иван Гришаев: Заменяются не все символы, а только те, что не входят в диапазон 0x20-0x7f (A-z, 0-9). Если у вас английский текст, то разницы не будет.

    \uxxxx - это код символа Unicode. Согласно стандарту JSON строки должны быть представлены Unicode-последовательностями. Это правило можно нарушать, но тогда никто не гарантирует корректный разбор JSON-документа со строками, скажем, на украинском.

    Преимущество JSON перед XML не в меньшем объеме данных, а в удобстве сериализации и парсинга. Одной функцией структура сворачивается в JSON, другой – обратно. Генерация и парсинг XML занимают больше времени и сил.

    11/21/12 Артемий Зайцев: Проверил с разными языками. В UTF всё работает. Еще у вас подстановок спецсимволов в строке. Если в тексте есть знаки / \ “, то JSON ломается.

    Сделал как-то так:

    Если Тип = Тип("Строка") Тогда
    	Возврат """" + MyJSONМаскировать(Объект) + """";
    ....
    Функция MyJSONМаскировать(Знач Стр)
    	Стр=СтрЗаменить(Стр,"\","\\");
    	Стр=СтрЗаменить(Стр,Символы.ПС,"\n");
    	Стр=СтрЗаменить(Стр,Символы.ВК,"\r");
    	Стр=СтрЗаменить(Стр,Символы.Таб,"\t");
    	Стр=СтрЗаменить(Стр,"/","\/");
    	Стр=СтрЗаменить(Стр,"""","\""");
    	Возврат Стр
    КонецФункции
    

    11/21/12 Иван Гришаев: Да, спасибо, только что сам обнаружил, что с кавычками косяк, нужно их экранировать заменой, как у вас. Завтра выложу новую версию функции.

    05/31/13 Кирилл: Спасибо автору!

    05/31/13 Зайцев Артемий Анатольевич: Кирилл, рано автора хвалить. Он только начинает учить 1С. Есть еще ошибки: (Формат(Объект, "ДФ=yyyy-MM-ddThh:mm:ss") - после буквы T ничего не пишет.

    05/31/13 Иван Гришаев: Вы комментируете старую версию функции. Вот новая. Там много чего исправлено. Эта крутится в продакшене уже больше года.

    05/31/13 Зайцев Артемий Анатольевич: Иван. В новой тот же косяк с датой:

    Возврат json(Формат(Объект, "ДФ=yyyy-MM-ddThh:mm:ss"));
    

    надо как-то:

    Возврат json(Формат(Объект, "ДФ=yyyy-MM-dd") + "T" + Формат(Объект, "ДФ=hh:mm:ss") );
    

    05/31/13 Иван Гришаев: Похоже, вы правы, спасибо. В моем проекте часы и минуты не нужны, не обратил внимания.

  • Личный кабинет Читаэнергосбыта для Андроида

    icon

    Выложил в Маркет свое первое приложение — личный кабинет абонента Читаэнергосбыта.

    Веб-версия кабинета работает уже второй год, на момент написания заметки зарегистрировано 3500 абонентов, передано 4000 показаний приборов, зарегистрировано 250 заявок.

    Теперь все это удобство доступно в смартфоне.

    На создание, тестирование и отладку ушло 3 месяца. Приложение взаимодействует с нашим сервером HTTP запросами, трафик копеечный.

    Так что если вы наш абонент, милости прошу установить и пользоваться.

    Комментарии из старого блога

    01/12/13 obmorrock: А где кроме маркета можно скачать apk? А то у меня на смарте маркет выпилен, а установить хочется….

    01/12/13 Иван Гришаев: Выслал почтой.

    04/23/13 Иванов Сергей: Уважаемый Иван! Установил и пользовался вашим приложением несколько месяцев всё работало прекрасно, но более недели уже не могу им воспользоваться. При нажатии “Войти” выдаёт сообщение “Ошибка сервера” при этом приходит сообщение, что “выполнен вход в личный кабинет дата время”. Что случилось?

    04/23/13 Иван Гришаев: Здравствуйте! С самим приложением все в порядке, неполадки возникают на стороне сервера, который возвращает данные. Я уже не работаю в Читаэнергосбыте, поэтому исправить ошибку не смогу, но дам знать коллегам.

    04/23/13 Иванов Сергей: Спасибо.

  • JSON-сериализация в 1С

    UPD: новая версия функции.

    Быдлоплатформа 1С не умеет работать с JSON, MD5, SHA, чем огорчает веб-разработчика. Ничего, научим: http://pastebin.com/4tF96gQH

    Пример:

    Запрос = новый Запрос(
    	"ВЫБРАТЬ ПЕРВЫЕ 5
    	|	Договоры.Код,
    	|	Договоры.Ссылка,
    	|	Договоры.ДатаЗаключения,
    	|	Договоры.Комментарий,
    	|	Договоры.Предопределенный
    	|ИЗ
    	|	Справочник.Договоры КАК Договоры"
    );
    с = новый Структура("foo, bar, baz, tab", 1, "Привет!", ТекущаяДата(), Запрос.Выполнить().Выгрузить());
    Сообщить(json(с));
    

    Результат:

    {
        "foo": 1,
        "bar": "Привет!",
        "baz": "2012-11-09T10.50.29",
        "tab": [
            {
                "Код": "ВСООЦ0050133",
                "Ссылка": "ВСООЦ0050133",
                "ДатаЗаключения": "2012-09-14T12.00.00",
                "Комментарий": "",
                "Предопределенный": false
            },
            {
            ...
            }
        ]
    }
    

    TODO: добавить некоторые типы данных (выборка из результата запроса, наборы записей).

  • Степень схожести строк (коэффициент Танимото)

    Иногда нужно определить степень схожести двух строк, т.е., насколько одна строка похожа на другую. Например, у вас есть список названий фильмов. Источники разные, нет никаких уникальных идентификаторов, только заголовки. При этом стоит учесть, что даже самые простые названия могут быть написаны по-разному: «ЗАЛОЖНИЦА 2» и Заложница 2. Очевидно, что сравнение этих строк в лоб ничего не даст: лишние символы, разный регистр.

    Строки можно рассматривать как множество символов. Две строки — два множества. Коэффициент Танимото позволяет определить степень схожести двух множеств:

    screenshot

    , где:

    • k — сам коэффициент от 0 до 1;
    • a — количество элементов в первом множестве;
    • b — количество элементов во втором множестве;
    • c — количество общих элементов в двух множествах.

    Изящная функция на Питоне:

    def tanimoto(s1, s2):
        a, b, c = len(s1), len(s2), 0.0
    
        for sym in s1:
            if sym in s2:
                c += 1
    
        return c / (a + b - c)
    

    Пара примеров:

    print tanimoto('Иван Гришаев', 'Гришаев И.В.')
    0.846153846154
    
    print tanimoto('tanimoto test 1', 'testing Tanimoto #2')
    0.7
    

    В Питоне работает т.н. утиная типизация, когда важен не тип объекта, а его поля и методы. Нетрудно заметить, что код функции требует от объектов методов длины, вхождения элемента и итерации. Это значит, что вместо строк можно передавать списки, кортежи, словари и другие структуры:

    print tanimoto(
        (1, 2, 3, 4, 5, 4),
        (4, 2, 5, 4, 9, 3),
    )
    0.714285714286
    

    Конечно, расчет коэффициента нужно производить с умом. Например, вычистить регулярными выражениями лишние символы или передавать строки в одинаковом регистре. И конечно, лучше оперировать строками в юникоде.

    Возвращаясь к нашему примеру:

    print tanimoto(
        u'«ЗАЛОЖНИЦА 2»'.lower(),
        u'Заложница 2'.lower(),
    )
    0.846153846154
    

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

  • Работа с DBF в Питоне

    Формат DBF, хоть и признан устаревшим, до сих пор широко используется в финансовых учреждениях. Он подходит для обмена табличными данными, такими, например, как отчеты и реестры платежей. Формат имеет простую логическую структуру, поэтому библиотеку для работы с ним можно написать самостоятельно. Классический DBF поддерживает основные типы данных — числа, строки, даты и булево. Благодаря этому дата, записанная в DBF, будет считата как дата, а не текстовая строка, которую будет необходимо парсить.

    Для работы с файлами DBF в Питоне потребуется библиотека dbfpy. Это, кстати, не единственное решение, есть еще библиотеки pyDBF и dbf. Сам я работал только с первой из трех, функционал полность устраивает.

    Приведу пару примеров: чтение и запись файла.

    from dbfpy import dbf
    
    # Открываем имеющийся файл.
    db = dbf.Dbf("dbfile.dbf")
    
    # Обход всех записей.
    for rec in db:
        print rec
    
    # Извлечение записи по номеру.
    rec = db[42]
    
    # Значения полей извлекаются по их именам.
    value = rec["VALUE"]
    account = rec["ACCOUNT"]
    date = rec["DATE"]
    
    # Всегда закрывайте файл.
    db.close()
    

    Запись нового файла немного сложнее, так как потребуется указать схему данных. Фрагмент кода из реального проекта:

    from dbfpy import dbf
    
    # Определяем набор полей файла. C — строка, N — число, D — дата, L — булево.
    # Для строк нужно указать длину, для чисел — количество разрядов целой и дробной частей.
    SCHEMA = (
        ("PSU",        "C", 64   ),
        ("TSO",        "C", 64   ),
        ("PAYMENT",    "N", 16, 0),
        ("SERVICE",    "N",  8, 0),
        ("DATE",       "D"       ),
        ("MRO",        "C", 64   ),
        ("TERMINAL",   "N",  8, 0),
        ("ACCOUNT",    "C", 16   ),
        ("SUMMARY",    "N", 16, 2),
        ("OPERATOR",   "N",  8, 0),
        ("SUPPLIER",   "N",  8, 0),
        ("TIME",       "C",  8   ),
        ("LAST_NAME",  "C", 64   ),
        ("FIRST_NAME", "C", 64   ),
        ("MIDDLE_NAM", "C", 64   ),
    )
    
    db = dbf.Dbf("dbfile.dbf", new=True)
    db.addField(*SCHEMA)
    
    # Обходим в цикле данные, которые необходимо записать в DBF.
    # В данном случае payments — объект QuerySet из Джанго.
    # На каждом шаге цикла создается новая запись и заполняются ее поля.
    for payment in payments:
        rec = db.newRecord()
        rec["ACCOUNT"] = payment.account
        rec["FIRST_NAME"] = payment.first_name.encode("cp866")
        rec["date"] = payment.date
    
        # Заполняем остальные поля...
    
        # Сохранение записи.
        rec.store()
    
    db.close()
    

    Готово, файл создан.

    Наверняка вы обратили внимание на кодирование поля payment.first_name. Это unocode-строка, и для того, чтобы записать ее в файл, необходимо сперва преобразовать в обычную строку в какой-то кодировке. Исторически сложилось так, что основной кодировкой для этого формата является OEM, она же DOS, она же cp866. Многие программы, например, офисные Эксель и Акцесс работают с DBF-файлами именно в этой кодировке. Чтобы созданные вами файлы читались в сторонних программах, преобразовывайте перед записью строки с кириллицей в cp866.

    Работать с DBF можно как с SQL-базой через драйвер ODBC. При этом именем таблицы является имя файла. Доступны все CRUD-операции на записями. Склеить два DBF-файла оператором JOIN, к сожалению, нельзя. Для работы с ODBC-источниками скачайте библиотеку pyodbc.

    import pyodbc
    
    # Строка, определяющая источник ODBC. DefaultDir — директория с DBF-файлом.
    s = "Driver={Microsoft dBASE Driver (*.dbf)};DefaultDir=d:\\temp"
    
    db = pyodbc.connect(s, autocommit=True)
    cursor = db.cursor()
    
    # Пример выборки.
    cursor.execute('''
    SELECT
        value,
        account,
        date
    FROM
        dbfile
    WHERE
        processed = 'false'
    ''')
    
    # Извлечение записи.
    row = cursor.fetchone()
    if row:
        print row
    
    # Закрываем курсор и ресурс.
    cursor.close()
    db.close()
    

    Вставка, удаление и обновление записей реализуются аналогично согласно SQL-синтаксису:

    cursor.execute('''
    DELETE FROM
        dbfile
    WHERE
        processed = 'false'
    ''')
    
    cursor.execute('''
    UPDATE
        dbfile
    SET
        account = 'test',
        value = 42
    WHERE
        id = 1
    ''')
    

    Какой способ работы с DBF задействовать в проекте — решать вам. dbfpy не требует сторонних зависимостей, написана на чистом Питоне, может работать в сервисах типа App Engine, однако, не столь быстра, как pyodbc. Последняя, напротив, быстрее, но зависит от платформы и иногда глючит на Винде (у меня были проблемы с ошибками в DLL-библиотеках). Для небольших проектов рекомендую использовать dbfpy, в промышленных масштабах — pyodbc.

    Комментарии из старого блога

    04/08/14 Городецкий: привет! получаю invalid syntax при from dbfpy import dbf. Подскажи пожалуйста, что не так?

    04/09/14 Иван Гришаев: Точка в конце не нужна. Или какая-то из букв кириллическая. Трейс должен показывать стрелочкой, где косяк.

    01/09/15 Ole: Отличный пост

    09/02/15 Дамир Аманов: в pyodbc как работать с кириллицой? в windows

    09/03/15 Иван Гришаев: Насколько помню, кодировать строки в cp2151, если не получается с юникодом.

  • Замечательный движок Эгея

    Этот блог работает на движке Эгея. Я узнал о нем из блога Ильи Бирмана (автора проекта). Поначалу мое отношение было скептическим — мало ли сейчас различных движков? Решив вести собственный блог, я перебрал несколько движков и КМС, и вышло так, что только Эгея не только удовлетворила все мои требования, но и приятно удивила в дальнейшем.

    Почему я не использовал Друпал? Его долго собирать. Это не готовая КМС, а конструктор. Установив Друпал, приходится еще полдня ставить модули и лазить в настройках. Эгея же просто работает. В ней нет хлама вроде опросов, древовидных тегов, визуального редактора, архива за прошлые года. Она минималистична и быстра.

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

    Пока что я вижу в движке два недостатка: вики-разметка и кодировка cp1251.

    Использование разметки вместо обычного ХТМЛ является правильным решением: набирать теги руками замучаешься, а визуальные редакторы выдают отвратительный код. Вот только Илья не угадал с разметкой, лучше было бы взять не вики, а маркдаун, он проще и удобнее. Впрочем, к вики быстро привыкаешь.

    Кодировка cp1251 устарела и отовсюду вытесняется УТФ, так как не позволяет использовать символы юникода и не дружит со многими языками. Эгею нужно перевести на УТФ обязательно, cp1251 — преграда на пути проекта к широкой аудитории.

    И тем не менее, Эгея — лучший движок для блога из всех, что мне приходилось видеть. Помимо очевидных плюсов, вроде быстрой установки и высокой скорости работы, в ней есть сюрпризы. Например, картинки вставляются перетаскиванием файла в браузер. Это этого получаешь дикий, нестовый восторг! Не нужно больше искать изображения в дурацком диалоге выбора файла!

    Эгея легко поддается темизации, написать свою тему для нее нетрудно. Движок поддерживает пользовательские блоки — это ПХП-файлики, содержимое которых выводится в определенное место, например, перед статьей, после статьи, в сайдбаре, в подвале и т.д. Мне понадобилось всего три таких файла — сайдбар с меню, область после статьи для социальных кнопок и подвал для джаваскрипта (метрика, подствека кода).

    Словом, нисколько не ошибся с выбором Эгеи. Отличный движок, желаю Илье не забрасывать и развивать прект.

  • Мысли о Друпале

    Друпал (анг. Drupal) — система управления содержимым, написанная на ПХП Дрисом Бёйтартом. Вместе с Вордпрессом и Джумлой входит в большую тройку КМС.

    Историю Друпала вы можете прочесть в Википедии. Ознакомиться с текущим состоянием дел можно на официальном сайте. Начинающим будет полезно зарегистрироваться на форуме Дупал.ру, сообщество активно, есть подборка обучающих статей.

    В этом посте я хочу выразить некоторые мысли, которые сформировались за долгое время работы с Друпалом. Это отдельные тезисы с краткими пояснениями.

    Гибкость системы. Главным достоинством Дупала является его гибкость. Не секрет, что любая КМС в той или иной степени ограничивает разработчика. Дрис и команда разработали систему модулей и хуков. Она позволяет менять поведение Друпала без правок ядра.

    Хуки — именованные функции. За хакерским словечком «хук» скрывается банальная вещь — функция, имя которой удовлетворяет шаблону <имя модуля>_<имя хука>. Эти функции должны располагаться в теле модуля. Друпал опрашивает модули на предмет наличия этих функций и вызывает их. При этом функция-хук должна либо вернуть какие-то данные, либо изменить те, что были переданы ей по ссылке. Хуков много, вызываются они в разное время. Некоторые модули могут определять собственные хуки.

    Множество модулей. Система модулей и хуков понравилась разработчикам. В настоящее время число всех модулей оценивается в несколько тысяч. В актуальном состоянии поддерживается около тысячи модулей. Написать свой модуль легко — это ПХП-файл с расширением *.module с функциями-хуками внутри. Описание каждого хука с примерами смотрите в документации.

    Не все в Друпале так идеально, как кажется. Друпал имеет солидный возраст, это зрелый программный продукт. Однако, некоторые его компоненты устарели и нуждаются в переработке. Например, работа с формами. В любом современном фреймворке форма, поля и валидаторы — это классы. Нужно расширить форму — наследуете от нее свой класс. Работа с классами проще, чем с хэш-массивами двойной вложенности. Друпал хранит переводы и кэш в базе, что отрицательно сказывается на производительности. Система нод (или сущностей) Друпала раскидывает поля по отдельным таблицам, вместо того, чтобы добавлять поля к имеющимся.

    Не делайте из Друпала культ. Начинающим веб-разработчикам кажется, что Друпал способен на все. Это правда, но лишь в теории. Легкость создания больших сайтов без написания кода компенсируется многими уровнями абстракций и чрезмерно сложной логикой. Приступая к новому проекту, спросите себя, так ли нужен здесь Друпал, нельзя ли обойтись чем-либо попроще? Например, вы решили вести блог. Стоит ли качать Друпал, ставить на него и настраивать кучу модулей, если проще взять специализированный движок?

    Любите Друпал не больше других средств разработки. Не зацикливайтесь на Друпале. Постарайтесь освоить несколько технологий, языков, фреймворков, КМС. С разнообразием приходит опыт. Заимствуйте удачные решения из одного проекта в другой. Старайтесь не привязывать удачные решения только к Друпалу. Например, если в модуле есть код рассылки смс, оформите его в отдельном файле и выложите на Гитхаб.

    Комментарии из старого блога

    08/19/12 jedi: Согласен со всем, жалко мало написали. Сам перехожу на yii

Страница 52 из 53