В одном проекте я использовал redis для хранения статистики, собираемой из нескольких процессов python на одной машине. Статистика складывалась в redis в hash или словарь. Попробовал заменить место хранения на словарь в питоне и вот, что из этого вышло:
from multiprocessing import Pool, Manager, Lock lock = Lock() manager = Manager() stats_dict = manager.dict()
Проще не получилось, так как в разделяемой памяти (Shared Memory) нету такого класса, как словарь в multiprocessing модуле. Код, демонстрирующий использование:
def save_stats(x): lock.acquire() if not stats_dict.has_key('test'): stats_dict['test'] = 0 for i in range(100): stats_dict['test'] += 1 lock.release() if __name__ == "__main__": pool = Pool(processes=4) pool.map(save_stats, [1, 2, 4, 5]) print stats_dict
Как видим одновременно запускаются четыре процесса, выполняющие процедуру save_stats. После окончания, в поле 'test' окажется 400. Никаких race conditions. Вот думаю теперь насколько это лучше просто redis. Выглядит примерно одинаково по эффективности.
Предыдущие два дня я провел в реализации TCP сервера на питоне слушающего определенный порт и при выполнении запросов использующего все ядра процессора. Первая реализация была проста и использовала ThreadedTCPServer:
import SocketServer class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler): def handle(self): data = self.rfile.readline() result = '' # request processing ...... self.request.sendall(result) server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) server.serve_forever()
И все бы хорошо, только python GIL в процессер обработки запроса не дает использовать больше одного ядра в один момент времени. К слову говоря, PyPy тут тоже не помогает. Можно конечно использовать вместо ThreadedTCPServer, ForkedTCPServer:
class ForkedTCPServer(SocketServer.ForkingMixIn, SocketServer.TCPServer): pass
Действительно, все ядра начинают быть задействованы на 100%, но только массовое создание и уничтожение процессов ресурсоемкая штука, при большом кол-ве запросов в секунду. Хочется иметь заранее запущенный пул воркеров, которым можно было бы передавать запросы на выполнение. Если все воркеры заняты, то запросы становились бы в очередь. И в питоне есть такая штука!
from multiprocessing import Pool if __name__ == "__main__": WORKERS = 4 pool = Pool(processes=WORKERS, maxtasksperchild=500)
, где maxtasksperchild кол-во выполненных задач одним воркером, после которого, он перезапускается, во избежание утечек памяти; WORKERS - кол-во процессов
Передать задачу на выполнение воркеру и получить результат можно так (внтури обработчика запроса):
def handle_task(data): result = '' # implementation ... return result class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler): def handle(self): data = self.rfile.readline() p = pool.apply_async(handle_task, args=(data, )) result = p.get(timeout=30) self.request.sendall(result)
В результате мы имеем на каждый запрос отдельный поток и в каждом потоке обработка запроса происходит в свом заранее запущенном процессе. Результат возвращается после завершения выполнения задачи в процессе и передается TCP/IP клиенту.
На этом можно было бы остановиться, но в моем случае, походу обработки задачи, мне нужно было возвращать TCP/IP клиенту прогресс выполнения задачи и только в конце возращать результат. Первое, что пришло в голову - это использовать multiprocessing.Pipe, потом multiprocessing.Queue и в конец multiprocessing.Manager.Queue для передачи промежуточных результатов из процесса в обработчик TCP/IP запроса от клиента. К своему удивлению, не смотря на подробную документацию (http://docs.python.org/2/library/multiprocessing.html) меня ждал полный провал. В случае Pipe and Queue просто не работает на Python 2.7, в случае multiprocessing.Manager.Queue, как-то работает на Mac OS X, но очень глючно работает под Ubuntu. В общем использовать такие вещи из потока обработки запроса практически невозможно, работает это только в случае глобальных переменных, созданных внутри блока "if __name__ == "__main__":"
Но один выход нашелся, оказывается можно передать сам TCP/IP сокет из потока обработки в процесс воркера и сделать это можно вот так:
from multiprocessing import Pool from multiprocessing.reduction import reduce_handle, rebuild_handle import socket import SocketServer def handle_task(data, h): fd = rebuild_handle(h) client_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM) result = '' # implementation ... client_socket.sendall(result) class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler): def handle(self): data = self.rfile.readline() h = reduce_handle(self.request.fileno()) p = pool.apply_async(handle_internal, args=(data, h)) p.get(timeout=30) if __name__ == "__main__": pool = Pool(processes=WORKERS, maxtasksperchild=500) server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) server.serve_forever()
Решение рабочее, но по ощущениям избыточное. Может у кого есть более простое решение этой проблемы?
При ответе на вопросы в рамках office hours (то есть ответы на вопросы от учеников от преподавателей курса) было как минимум два интерсных вопроса-ответа. Далее вольный перевод по памяти с моими возможными добавками:
Ученик: Почему вы делаете эти курсы бесплатно для всех?
Себастиан: Мы делаем это из-за вас (показывает в экран). because of you! Так восхитительно делиться знаниями с таким огномных количеством людей. У меня никогда не было такой огромной группы!
Ученик: Что вы посоветуете читать?
Себастиян: Ничего не читайте. Выберите задачу, которая вам интересна (она может быть даже уже решена кем-то) и попробуйте решить ее. И когда вы ее решите своим способом, то потом вы можете почитать как она решалась другими. И я так же гарантирую (что-то вроде этого слова), что пока вы решаете такого рода задачи вы увидите около 10 задач, которые еще не решены и вот их-то и будет понастоящему интересно решать.
На этот раз пост не технический, а самый ни на что пиарный :) Полгода работы подошли к первому логическому рубежу, чем я и хочу поделиться и попросить потестировать наш сервис управления идеями. Статья на Хабре с описанием проекта прилагается.
Поигрался вчера с PyPy 1.5 на 64-битном Маке. Мой простой тест производительности отрисовки простого темплейта джанго показывает увеличение скорости всего процентов на 20. Честно говоря намного меньше чем официальный бенчмарк от команды разработчиков. Могу предположить, что значительный прирост наблюдается наверно только в Linux.
Из хорошего: можно создать виртуальную среду с помощью virtualenv, работают все библиотеки написанные на чистом Питоне. Даже установилась библиотека pylibmc для работы с memcached. Но не удалось поставить psycopg2 (но есть специальная версия pypy от Alex Gaynor, то есть одного из core developer). На удивление не поставился PIL, хотя в интернете пишут, что под версию 1.4 ставился.
Дайте знать, кто-то пробовал PyPy 1.5 под линукс, какой прирост скорости наблюдается? Удалось ли кому запустить PIL и psycopg2?
Так как в блог уже достаточно давно сыплется достаточно большое количество спама и защита Akismet не помогает, то решил сегодня добавить в комментарии простую captcha от библиотеки django-simple-captcha, с упрощенным алгоритмом искажения символов. Посмотрю на ее эффективность в защите от спама и напишу о результатах где-то через месяц. Так же надеюсь, что она не доставит большого неудобства, тем кто действительно хочет написать мне ценный комментарий :)
Не так давно Амазон запустил сервис Simple Email Service или сокращенно SES. Судя по отзывам в интернет, цены на отправку писем самые низкие, всего 10 центов за 1000 писем + трафик 15 центов за гигабайт исходящего трафика (первый гигабайт бесплатно). У конкурентов обычно в 10 раз дороже.
И когда у нас в проекте появилась потребность отправки большого кол-ва писем, то решил попробовать SES. Сначала, идя по инструкции по установке и настройке, долго казалось, что отправлять письма можно только через спец. скрипт написанный на Perl. О боже, нужен был не только Perl, а так же к нему еще поставить ряд библиотек. После непродолжительной депресии, помогло наконец почитать README, находящееся в папке со скриптом. Там были даны простые инструкции по установке дополнительных библиотек! :)
Параллельно, как написано в амазоновской инструкции, сделал запрос на открытие мне доступа к SES в production mode. Это значит, что я могу отправлять письма на любые адреса, а не только на проверенные. Подтверждение от амазона пришло в тот же день вечером. Оперативно.
Но проблема отправки писем через скрипт из командной строки по прежнему не радовала. Как это интегрировать с джангой? Попытки настроить интеграцию с sendmail на сервере по описанию в доке Амазона не увенчалась успехом. И тут счастье наконец наступило в лице свежеиспеченной библиотеки django_ses. Оказалось умельцы уже сделали интеграцию с джангой за счет написания своего почтового бэкэнда. Плюс доступ к статистике отправки почты. Все просто и удобно.
Будем пробовать на практике и понемногу допиливать django_ses :)
Соответственно обновилась и библиотека django-celery, упрощающая работу с celery. В новой версии произошло существенное изменение: произошел переход с библиотеки carrot на kombu. Как пишут в релизе, kombu дает следующее:
Переход на kombu в том числе значит, что библиотека ghettoq больше не нужна для работы с Redis. Все уже есть в самом celery.
Если коротко, то это библитека организации асинхронной очереди задач или работ. Основной упор на задачи, выполняющиеся в реальном времени (асинхронно), но планировщик выполнения задач так же поддерживается. Читать описание дальше...
Очень удобно работать с celery через библиотеку django-celery. Ставим через pip + библиотеку работы с redis:
pip install django-celery pip install redis
Заодно поставиться и celery и все нужные библиотеки. Останется только поставить Redis. Настройка проста, в settings.py нужно сделать всего две вещи: в INSTALLED_APPS добавляем "djcelery" и для работы через Redis добавляем следующий код:
import djcelery djcelery.setup_loader() BROKER_BACKEND = "redis" BROKER_HOST = "localhost" BROKER_PORT = 6379 BROKER_VHOST = "0"
Для асинхронных задач: В папке приложения в проекте джанго создайте файл tasks.py. Задачи в таком файле будут автоматоматически распознаны celery при запуске. Пример задачи в файле tasks.py:
from celery.decorators import task @task() def send_email(from, to, subject, body): # send email...
Запускаем celery из папки проекта НЕ в демон режиме:
python manage.py celeryd -l info
В коде, такую задачу вызываем простой командой:
send_email.delay(from, to, subject, body)
В этом году я начал вести свой блог для разработчиков. Первый новый пост был добавлен в блог 16 февраля. За время прошедшее с этого момента, получились следующие цифры:
Спасибо что читали и оставляли свои ценные замечания! С новым годом, друзья!
В процессе работы над проектом (см. мой предыдущий пост для введения в тему) с использованием приложения django-sphinx, последний пришлось доработать до наших потребностей. Представляю мой fork от django-sphinx, в котором появились следующие возможности:
set_options
добавлен параметр only_sphinx
, которая возвращает результат запроса из Sphinx не делая запроса в БДTag.search.group_by('types', SPH_GROUPBY_ATTR)
Tag.search.group_by('types', SPH_GROUPBY_ATTR).group_distinct('status')
Tag.search.query('(белая кошка) | собака | ёжик').\
set_options(mode='SPH_MATCH_EXTENDED2', rankmode="SPH_RANK_BM25", sort='SPH_SORT_RELEVANCE')
Tag.search.query('соба*')
. Чтобы это заработало в sphinx.conf в разделе index application_tag нужно прописать следующие строки (начинать поиск начиная с 3 символов):enable_star = 1 min_prefix_len = 0 min_infix_len = 3
Итак, на этот раз ищу профессионального Джанго-разработчика в проект которым я занимался около полугода. Сильные знания именно Джанго не обязательны, но профессиональным программистом нужно быть :) Программист ищется в проект istrahovka.ru. Краткая суть проекта: веб-сервис подбора и покупки страховых продуктов от ведущих российских страховых компаний как для обычных пользователей, так и для страховых агентов. На данный момент доступно только два страховых продукта: ОСАГО и КАСКО и 5 страховых компаний. В ближайшей перспективе планируется взять второго разработчика для совместной работы над проектом.
Зарплата в районе 90 тыс. рублей. Возможно какое-то время поработаем вместе в качестве меня руководителя разработки :)
Передавайте эту вакансию своим друзьям и друзьям друзей и пишите в комментариях о кандидатах :)
Upd: Город Москва, но возможна удаленная работа. В процессе работы скорее всего потребуется пару раз (не чаще раза в месяц), приезжать в Москву. В общем это по ситуации, но скорее всего потребуется, поэтому лучше жить не слишком далеко от Москвы, чтобы вы могли приехать.
Upd: Вакансия закрыта.
В проекте, в котором я сейчас участвую, одним из центральных элементов является полнотекстовый поиск по базе данных продуктов объемом около 1 млн. записей. У ребят уже был реализован поиск, используя встроенные возможности Postgresql (поле типа TSVector и специальный полнотекстовый индекс). Но скорость поиска достаточно низка, плюс усложняющая логику реализация в ORM Джанги. Поэтому возникла идея попробовать поиск через Sphinx. С этого момента sphinx приятно удивил меня несколько раз своими возможностями, а удовольствие от работы с ним с каждым разом только возрастало :) Если в кратце, то оказалось, что sphinx заменяет собой не только полнотекстовый поиск в базе данных, но фактически вообще поиск в базе данных, а так же группировку и сортировку результатов. Итак, по порядку.
Во-первых, скачиваем архив с исходниками Sphinx-1.10beta. Там есть несколько вкусных плюшек, без которых мне не захотелось жить, по сравнению с версией 0.9.9 :) Компилируем и устанавливаем, с поддержкой Postgresql:
tar -xzf sphinx-1.10-beta.gz cd sphinx-1.10-beta ./configure --prefix=/usr/local/sphinx --with-pgsql-includes=/opt/local/include/postgresql84 --with-pgsql-libs=/opt/local/lib/postgresql84 --with-pgsql make sudo make install
Настраиваем линки к индексирующей утилите и демону Sphinx для удобства:
ln -s /usr/local/sphinx/bin/searchd searchd ln -s /usr/local/sphinx/bin/indexer indexer
Для интеграции Sphinx с Django я попробовал библиотеку Django-sphinx и остался доволен. Как мне говорили, какое-то время назад она была еще сыровата, но сейчас она меня вполне устраивает и легко поддается расширению. Единственный недостаток пожалуй, что похоже она не будет в ближайшее время поддерживаться создателем David Cramer, так как похоже у него просто теперь нет на это времени из-за его перехода в команду проекта Disques. Но уже сейчас на GitHub есть 12 форков библиотеки с разными расширениями функциональности. Я в том числе собираюсь в ближайшее время создать свой :)
Установка: pip install django-sphinx
Если хотите разобраться быстро, то просто пойдите на страницу django-sphinx по ссылке выше. Там достаточно понятно описаны основные возможности. Я же опишу все подробно и плюс несколько продвинутых фишек, для которых пришлось покопаться в исходниках. Итак, прежде всего нужно добавить в settings.py переменную:
# Sphinx 0.9.9 + SPHINX_API_VERSION = 0x116
Для добавления поиска через sphinx с указанием веса каждого полнотекстового поля в модель Джанго пишем:
from djangosphinx.models import SphinxSearch class Tag(models.Model): title = models.CharField(unique=True) description = models.TextField() types = models.ManyToManyFields(TagType, verbose_name=u'типы тэга') status = models.SmallIntegerField(choices=[(1, u'первый статус'), (2, u'второй статус')]) search = SphinxSearch(weights={ 'title': 100, 'description': 30 })
Дополнительно при инициализации класса SphinxSearch можно задать название индекса, режим ранжирования результатов и т.д.
Далее нужно создать конфигурационный файл для sphinx. Тут нам тоже поможет django-sphinx, так как он умеет создавать либо полностью, либо примерно половину этого файла. Для этого добавим библиотеку djangosphinx в INSTALLED_APPS проекта. Затем, в корне проекта пишем:
./manage.py generate_sphinx_config <application name>
Для примера модели выше получаем:
source application_tag { type = pgsql sql_host = host sql_user = user sql_pass = password sql_db = database sql_port = sql_query_pre = sql_query_post = sql_query = \ SELECT id, title, description, status\ FROM application_tag sql_query_info = SELECT * FROM `application_tag` WHERE `id` = $id sql_attr_uint = status } index application_tag { source = application_tag path = /var/data/application_tag docinfo = extern morphology = none stopwords = min_word_len = 2 charset_type = utf-8 min_prefix_len = 0 min_infix_len = 0 }
Значения переменных sql_host, sql_user, sql_pass, sql_db, sql_port
будет заполнено из вашего settings.py. application - название приложения в котором объявлена модель. Рекомендую сразу заменить morphology = none
на morphology = stem_enru
для учета морфологии русского и английского языков. Теперь вручную в будущий конфиг-файл нужно будет только добавить служебный раздел sphinx. У меня он такой:
searchd { # какой порт и какой протокол "слушает" служба listen = 3312 # файл с логами log = /usr/local/sphinx/var/log/searchd.log # файл с логами поисковых запросов query_log = /usr/local/sphinx/var/log/query.log # PID file, searchd process ID file name # mandatory pid_file = /usr/local/sphinx/var/log/searchd.pid }
Все вместе сохраняем в файле sphinx.conf. В общем случае можете называть файл как хотите, но это название файла по умолчанию, который ищет в текущей папке демон searchd. Остается создать индексы sphinx командой: indexer --config sphinx.conf --all
и запустить демон командой searchd
.
Теперь самое интересное :) - что мы можем делать. Очевидно можем делать полнотекстовый поиск с учетом морфологии русского и английского языка:
Tag.search.query(u'тэгу')
Еще интереснее - можем искать так же по атрибутам. В нашем примере выше, атрибутом является поле status:
Tag.search.query(u'тэгу').filter(status=[1, 2])
Мы можем искать по диапазону:
Tag.search.query(u'тэгу').filter(status__range=[1, 3])
В версии 0.9.9 поддерживаются так же следующие типы атрибутов: sql_attr_bool, sql_attr_float, sql_attr_timestamp
. В версии 1.1 дополнительно добавлен часто необходимый строковый тип атрибута: sql_attr_string
. Следует отметить, что текстовый атрибут и другие атрибуты сохраняются вместе с основным индексом и поиск по ним напоминает поиск по полям в обычной базе данных, но быстрее. Впрочем текстового атрибута оказалось создателям sphinx мало, поэтому так же было добавлено специальное текстовое поле sql_field_string
, которое одновременно является и текстовым атрибутом и полнотекстовым полем. Примечание: на данный момент django-sphinx не поддерживает текстовые атрибуты.
А теперь переходим к действительно интересным вещам: мы можем искать по ManyToMany полям в модели используя Multi Value Attribute (MVA). Это нам дает устранить еще одно узкое место баз данных в плане быстродействия и масштабирования - join таблиц. Сначала пропишем MVA атрибут в конфиге sphinx в конце раздела source application_tag:
sql_attr_multi = uint types from query; SELECT tag_id, typetag_id \ FROM application_tag_types
теперь мы можем искать по нему, как и по другим атрибутам:
Tag.search.query(u'тэг').filter(types=[1, 2, 3])
Радуемся дальше :) В sphinx 1.1 было добавлена поддержка поля sql_joined_field
. Для чего оно нам? Представим стандартную ситуацию, например, у нас есть модель товар. К товару можно прикрепить несколько тэгов. Потом мы хотим найти все товары, через полнотекстовый поиск sphinx, у которых есть данный тэг. Без данного поля нам скорее пришлось бы сделать два запроса к sphinx. Сначала найти все тэги. Потом все товары у которых есть один из найденных тэгом. Теперь же мы можем без всяких join'ов обойтись одним запросом, сразу находя товары по их тэгам. Объявляем поле в конфиг-файле, например так:
sql_joined_field = tags_text from query; SELECT product_id, title \ FROM application_product_tags apt left join application_tag at on at.id = apt.tag_id \ order by product_id ASC
Примечание: данные, должны быть обязательно отсортированы по товарам.
Не забываем переиндексировать Sphinx. Теперь при обычном полнотекстовом поиске, так же будет производиться поиск и по этому полю.
Еще одна радость использования Sphinx: мы можем группировать результаты поиска по любому атрибуту или группе атрибутов:
from djangosphinx.apis.current import SPH_GROUPBY_ATTR Tag.search.query(u'тэг').filter(types=[1, 2, 3]).group_by('status', SPH_GROUPBY_ATTR)
В результате sphinx вернет для каждой группы лучший результат, а так же в специальном дополнительном поле @count число элементов в группе. К полю @count можно будет достучаться в дальнейшем так: item._sphinx['attrs']['@count']
И последняя возможность Sphinx, о которой хочу упоминуть в этой статье - вы можете сортировать как по весам, так и по атрибутам:
Tag.search.query(u'тэг').filter(types=[1, 2, 3]).order_by('status')
Дополнительно django-sphinx поддерживает команды select_related и extra, которые передаются в ORM джанго. Не проблема будет добавить так же ORM команду filter
, если после поиска в sphinx мы хотим дополнительно отфильтровать результат с помощью базы данных. Мне же, на данный момент, удалось обойтись исключительно поиском через sphinx, так что дополнительной фильтрации не потребовалось.
Как оказалось sphinx, помимо полнотекстового поиска, закрыл собой сразу несколько проблемных мест с быстродействием и масштабируемостью поиска. Благодаря использованию MVA атрибутов и sql_joined_field полей, а так же возможности сортировки и группировки результата. И все это вместе с в несколько раз более высокой скоростью поиска, а так же высокой скоростью переиндексации данных. В предстоящем релизе 1.1 будет так же добавлена возможность обновления индекса в реальном режиме.
Тем временем мое знакомство со sphinx продолжается и я еще обязательно напишу на эту тему.
Похоже достойная замена Apache для развертывания python-приложений на сервере дошла до момента, чтобы это попробовать в деле. uwsgi сам по себе активно развивается. Уже реализована поддержка нового протокола Web3, чтобы приложения python 3.x смогли работать под web-серверами. Как только появиться возможность, обязательно попробую запустить проект под nginx + uwsgi.
Питоновская библиотека pytz это просто благодать, сошедшая на меня сегодня :) Конечно большинство знает про эту бибилотеку, просто я впервый раз ее сегодня использовал. Если мы знаем название локальной time zone, то преобразовать серверное время в локальное очень просто (переход на летнее время тоже учитывается):
from pytz import timezone from datetime import datetime tz = 'Europe/Moscow' server_time = datetime.utcnow() client_time = timezone(tz).fromutc(server_time)
Update: Как подсказывает bw в комментариях, есть еще одна интересная библиотека dateutil
По наивности попробовал загрузить файлы на сервер, используя JQuery-команду post:
$.post(url, $("#myForm").serialize());
HTML-код формы, скажем такой:
<form id="myForm">
<input type="text" name="text"/>
<input type="file" name="image"/>
</form>
Оказалось через AJAX так делать нельзя, если в форме есть файлы :) Как же тогда сделать? Одно из решений - плагин "forms" к jQuery. В коде страницы пишем следующее:
script type="text/javascript" src="/media/js/jquery.form.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// bind 'myForm' and provide a simple callback function
$('#myForm').ajaxForm();
// submit form
$("#myForm").ajaxSubmit({
url: url,
iframe: true,
dataType: 'json',
beforeSubmit: function(arr, $form, options) {
// some code here
},
success: function(data) {
// some code here
}
});
})
, где параметр iframe: true
рекомендую установить, если идет загрузка файлов. Параметр dataType: 'json'
- задает тип возвращаемых данных.
Попробовал работу плагина в Firefox 3.6, Chrome 5 и Internet Explorer 8. Работает без проблем. И на последок описание API плагина.
Мне всегда доставляет удовольствие узнать что-то новое в программировании или технологиях. И недавно мне повезло. Аж целых две новые штуки за раз! В этом посте расскажу о первой, а в следующем о второй.
Итак задача стояла: загрузить на сервер zip-архив картинок товаров, пройтись на сервере по всем именам файлов в архиве, производя над каждым файлом определенные действия. Следуют сказать, что названия файлов были чрезвычайно важны, так как название файла - это код товара. По этому коду в базе находился нужный товар и к нему крепился распакованный файл из архива. Все естественно работало на ура, пока названия были англоязычные, но как только коды товаров, а соответственно и названия файлов стали попадаться с русскими буквами все поломалось. И что же обнаружилось?
open(filename, 'w')
.Итак, код распаковывающий по-файлово zip-архив с русскими названиями файлов в нем, работающий как на архивах созданных под Windows, так и под Mac (сам код работает успешно под Mac и Unix) будет выглядеть так:
from zipfile import ZipFile
import os
# путь для распаковки файлов
path = os.path.join(settings.PROJECT_DIR, 'media/upload/products')
f = ZipFile(filename, 'r')
for name in f.namelist():
try:
unicode_name = name.decode('UTF-8').encode('UTF-8')
except:
unicode_name = name.decode('cp866').encode('UTF-8')
# some analyzing of unicode_name and execute some actions
# ...
file_name = os.path.join(path, unicode_name)
f2 = open(file_name, 'w')
#f.extract(name, path) # works only for python 2.6+
f2.write(f.read(name))
f2.close()
f.close()
Update: В комментарии подсказывают chardet - универсальный детектор кодировки
Мне нужно было передать в функцию параметр, в функции он изменяется и снаружи функции видно изменение. То есть фактически передать в функцию переменную по ссылке. Оказалось в Питоне с этим хитро. Есть изменяемые и неизменяемые переменные. Зависит от типа. Например, строки неизменяемый тип, а списки изменяемый. Соответственно строки передаются в функцию по значению, а список по ссылке. Пример параметра списка:
def test(a): a.append('new element') a = ['first element'] test(a)
Результат в переменной "а": ['first element', 'new element']
Если есть другие варианты явно указать, что параметр функции передается по ссылке, прошу в комментарии к посту.
Update: Кому интересно - загляните в комментарии, там тема расскрыта полностью.
Недавно закончил эксперименты с печатью "серъезных" документов из различных браузеров. Цель: возможно ли сделать документ с высокой точностью только с помощью HTML+CSS. (я имею ввиду, что документ визуально выглядит после распечатки, так же как и бумажный оригинал, отклонение не более 2-3 мм). Эксперимент проводил над следующими браузерами: IE 8, Firefox 3.6, Chrome 5.
Получается следующая картина:
- в IE8 и Firefox 3.6 можно добиться распечатки документа близкого к оригиналу, если все размеры в документе указаны в миллиметрах. В обоих браузерах есть настройки отступов страницы, печатать или нет header and footer и фон элементов.
- Google Chrome печатает нормально, но оказалась засада. У него вообще нет настроек параметров страницы перед печатью. В результате Chrome всегда печатает служебную информацию в header и footer каждой страницы и отключить это невозможно. Так же невозможно включить печать фона элементов (оказалось, что это отдельно нужно включать в настройках браузера).
- Opera показывает документ отлично от остальных браузеров. И распечатать пока тоже неудалось из-за поломки принтера.
Итог: идея оказалась в целом рабочей, но к сожалению не на всех распространенных браузерах.
Update: Печать под Мак из этих же браузеров + Safari (кроме конечно IE 8), выглядит хуже: невозможно настроить отступы и служебную информацию в header и footer.
Оказалось, что одним из лучших инструментов для конвертирования вордовских, экселевских, pdf и прочих документов в html являются Google Docs. Получаемый html-файл (плюс отдельно картинки) соответствует оригиналу и компактен. Сравнивал с возможностями MS Office и OpenOffice.
Потребовалось в проекте зашифровать данные достаточно надежным алгоритмом, например AES. Для этих целей есть конечно хорошая библиотека M2Crypto или есть еще PyCrypto. Но на сервере, где крутиться проект, нельзя поставить библиотеку, которая имеет в составе cишный код, так как это простой виртуальный сервер.
Покопавшись в интернете, не сразу, но нашел то, что надо. Криптографиеская библиотека tlslite, реализованная на чистом питоне.В том числе в ней есть быстрая реализация AES алгоритма. Правда пришлось закомментировать пару строк в файле tlslite/utils/Python_AES.py
, чтобы не ругалось на то, что длина кодируемого текста не кратна 16. На самом деле работает с любой длиной текста.
Например, так можно зашифровать и расшифровать текст в джанго-приложении:
import base64
from django.conf import settings
from tlslite.utils.Python_AES import Python_AES
aes = Python_AES(settings.SECRET_KEY[0:16], 2, settings.SECRET_KEY[16:32])
s = base64.encodestring(aes.encrypt('test'))
print s
print aes.decrypt(base64.decodestring(s))
![]() Ник: magic
Мой ЖЖ |
Интересноеpsycopg2 + ctypes - 21.02.2012
Переписанный psycopg2 для работы с ctypes под PyPy 1.6+ Simulating select_related() on a GenericForeignKey - 20.07.2011
Django patterns, part 4: forwards generic relations Очень пригодилось для проекта - выборка всем GenericForeignKeys одним запросом к базе. Рекомендую, кто сталкивался. python-handler-socket library - 03.02.2011
Библиотека на питоне для работы с HandlerSocket - специальным плагином для работы с MySQL в режиме NoSQL. Производительность сравнима или превосходит memcached. http://l-o-n-g.livejournal.com/153756.html - описание использования и тестирования HandlerSocket Realtime Web: TornadoIO + Socket.io - 28.01.2011
Интересная серверная библиотека поверх Торнадо + клиентская часть в виде библиотеки Secket.io поддерживающая следующие протоколы для организации непрерывного канала с сервером: Websocket, Flashsocket, XHR multipart, XHR polling, JSONp, HTMLFile (IE only) Django 1.3 Cache improvements - 07.01.2011
В Django 1.3 систему кэширования довели до ума. Из новых прикольных штук: 1. можно указывать несколько кэш-бэкэндов (так же как в случае баз данных): новая переменная CACHES; 2. появилось понятие версии кэша (есть функция для инкрементирования версии); 3. можно задать свою функцию для формирования префикса для ключа; 4. Добавлена поддержка библиотеки pylibmc (самая быстрая из всех для работы с memcached) django-multihost - 23.12.2010
Приложение упрощающее работу с несколькими сайтами в одном проекте, меняя SITE_ID на лету в зависимости от названия домена. django-test-utils - 12.12.2010
Набор утилит для тестирования Джанго проектов. Спасибо Роме Ворушину за наводку PyPy 1.4 - 27.11.2010
Сравнение скорости работы Джанго с cPython 2.6.2 Быстрее в 7 раз! Наконец-то 64 битная версия! Версия уже используется в production django-extauth - 22.09.2010
Extended authorization framework for Django (also 1.2), including field-level permissions and role-based permissions Javascript templates - 21.09.2010
Сохраню пару ссылок на интересные шаблонизаторы на javascript, как замена шаблонам на сервере. Второй с поддержкой джанго-шаблонов. И еще один очень интересный tempest: jquery + django template синтаксис django packages site - 17.09.2010
Django Packages - reusable apps, sites, tools, and more for your Django projects. Очень полезный сайт. Все пакеты разбиты по категориям. Можно сравнить пакеты с одинаковой функциональностью по популярности, продолжается ли еще его разработка и т.д. и выбрать лучший. django-sentry - 08.09.2010
Логирование в базу джанго - ошибок, замена стандартной отправке писем об ошибках. Удобная панель просмотра результатов логирования. При использовании нескольких баз данных (Django => 1.2) позволяет указать базу в которую будет производиться логирование. Альтернативное джанго-приложение для логирования: django-lumberjack django-formwizard - 08.09.2010
Django-formwizard is a reusable app to work with multi-page forms. Besides normal Forms, it supports FormSets and ModelForms. То есть, если нужно разбить форму на несколько страниц (шагов) и сохранить данные из всех шагов в базе на последнем шаге, то django-formwizard - это то что нужно. Данное приложение постепенно идет на замену стандартного form-wizard. Django Admin Tools - 08.07.2010
Описание отличного приложения позволяющего очень гибко кастомизировать стандартную Джанго админку. Ссылка на сам проект Релиз Django 1.2 - 17.05.2010
Выдержка из текста релиза: "После многих месяцев работы, мы с гордостью заявляем о выпуске Django 1.2. Так много крутых штук в этом релизе, что даже простое перечисление не может дать полной картины. Вы должны просто пойти прочитать заметки о релизе, чтобы все это увидеть, а затем перейти на страницу скачивания и урвать себе копию." Скорость разработки веб-приложений на Django - 23.04.2010
В статье описывается измерение скорости разработки веб-приложений на Python + Django по сравнению с ASP.NET. В результате разработка на Python + Django оказалась в примерно в два раза бестрее, чем на ASP.NET Using CPython extension modules with PyPy natively - 12.04.2010
Парни не перестают радовать и скоро выпустят поддержку модулей расширения CPython. С моей точки зрения останется еще поддержка 64-битного режима и желательно Python 2.6-2.7 и PyPy действительно можно будет рассматирвать как замену CPython, дающую действительно большой прирост скорости Erlang Factory SF Bay Area 2010 - 01.04.2010
Так как в прошлом я программировал на Erlang, то тема развития этого языка мне близка. На странице представлены презентации многих интересных докладов с прошедшего Erlang Factory SF Bay Area 2010, такие как: Erjang - A JVM-based Erlang VM, Erlang SMP support - behind the scenes, Fast Enough (применение NIF, доклад от Майкрософт), JavaScript CouchApps with CouchDB, Latest news from the Erlang/OTP team at Ericsson и другие. Вышел Python 2.6.5 - 21.03.2010
19 марта был выпущен релиз Python 2.6.5, исправляющий несколько дюжин багов. Новый релиз уже доступен в мак-портах. Новой функциональности в ветке 2.6 больше не предполагается. Thread-safe Django cache backend for pylibmc - 17.03.2010
Реализация потокобезопасного кэш-бэкэнда для Джанго с использованием библиотеки pylibmc. Hidden python features - 13.03.2010
Отличная подборка интересных особенностей языка Питон в одном месте. PyInstaller - 12.03.2010Программа для конвертирования приложений на Питоне в исполняемый файл под Windows, Linux и даже под мой любимый Mac OS X (пока из транка) со всеми нужными библиотеками для работы. Целью проекта является автоматическое отслеживание зависимостей со сторонними распространенными библиотеками прямо "из коробки" без каких либо дополнительных настроек. Проект активно развивается, в баг-трекере есть даже тикет для поддержки Джанго :) Pip, virtualenv и virtualenvwrapper - 02.03.2010
Рома Ворушин, понятным языком про pip, virtualenv и virtualenvwrapper. Про такие возможности pip я и не знал :) johnny-cache - 02.03.2010
Интересное решение для кэширования всех SQL-запросов в Django. При изменении любой таблицы, участвующей в Select, кэш сбрасывается. Пугает только, что кэширует все запросы, часто нужно кэшировать только определенные. Деревья в админке django - 27.02.2010
Простой вариант подключения дерева в админку Джанги. В комментариях к статье есть ссылка на еще один вариант подключения дерева в админки, который на вскидку еще проще: FeinCMS tree editor И в завершении темы отличная библиотека для django работы с деревьями: treebeard New GIL in Python 3.2 - 18.02.2010
The new GIL does not eliminate the GIL--it makes it better. Namely, a significant reduction in all of that thrashing and extra signaling overhead Описание новой функциональности Django 1.2 - 16.02.2010
With each new release, Django offers new features and techniques to simplify web development. Django Advent brings you articles about these new features and the techniques they make possible, often written by the feature's author. Context Manager for timing - 16.02.2010
Прекрасный пример кода: одновременно Context Manager и декоратор для измерения времени выполнения кода Материалы продвинутого уровня по Питону - 16.02.2010
Подборка книг и статей для углубленного изучения языка Easy fabric deployment - 16.02.2010
Fabric- библиотека, позволяющая легко разворачивать вашу систему на боевых или stage серверах запуском всего лишь одной команды django-pingback - 16.02.2010
Джанго приложение от Ивана Сагалаева для реализации tracebacks, которое я скоро буду использовать в этом блоге Декораторы Python - 16.02.2010
Простое и понятное описание декараторов в Питоне от Ромы Ворушина с примерами кода |