Работа и вакансии для программистов
В связи с участившимися вопросами о поиске программистов и интересных вакансий, решил организовать у себя в блоге отдельный раздел.
Я уверен, что работа или сотрудник, найденные по личным рекомендациям, имеют больший шанс удовлетворить запросы как работодателя, так и соискателя. Так получилось, что у меня много друзей в реальном и виртуальном мире — программисты, разработчики, админы и другие ИТ-специалисты. Многие из них работают уже в менеджменте или на топовых позициях, плюс ко мне периодически обращаются компании и люди, которых я консультирую с просьбой помочь в поиске сотрудников. Поэтому, для небольшой организации процесса нахождения работодателей и соискателей я решил вести личную базу вакансий и резюме. Также я буду рад помочь моим читателям в этом вопросе.
Чаще всего ищутся разработчики со знанием Python, Ruby и JavaScript. Если вы пишите на PHP, CSS/HTML, хороший управленец, пиарщик или занимаетесь веб-дизайном, также добавьте ваше резюме.
Мои партнеры чаще всего предлагают контрактную работу в западных стартапах или рунет-проектах. Если вы тоже работодатель или вы просто ищите специалиста, пишите мне на личную почту dobrych [at] gmail.com
На сегодня есть две позиции, на которые требуются специалисты с опытом:
- Ruby программисты для разработки и поддержки сайтов, построенных на Rails.
- JavaScript программист с знанием ExtJS.
Последняя свежая информация и анкета для соискателя всегда на странице «Работа и вакансии».
Для работодателей есть возможность размещения баннеров и выделенных объявлений (виджетов).
Django signals по-новому 2
На пути к 1.0 релизу Django претерпевал немало радикальных изменений. Одно из них рефакторинг системы сигналов.
Если вы первый раз читаете и не в курсе «что это такое и с чем его едят», то скажу в двух словах. Это система реагирования на события приложения. Любой JavaScript или прикладной UI программист хорошо знаком с системой событий (event) — клик мышкой, нажатие горячей клавиши и т.п. Для программистов серверной части веба все выглядит немного по другому. Есть HTTP-запрос и есть его обработчик, анализируется как правило URL на предмет «кому отправлять запрос». Но на самом деле это та же система сигналов-событий, только узкопрофилированная под обработку HTTP-запросов.
Оказывается серверная часть веб-приложения тоже может, и я уверен, просто должна генерировать намного больший спектр сигналов, чем просто обработку URL и данных запроса. С чем успешно и справляется Django. Теперь немного прозы. Какие же события может ловить Django «из-коробки».
pre_init
— перед запуском метода-конструктора__init__()
модели;post_init
— после выполнения метода__init__()
модели;pre_save
— перед сохранением экземпляра модели в базу;post_save
— после успешного сохранения экземпляра модели в базу;pre_delete
,post_delete
— перед и после удаления экземпляра модели из базы;post_syncdb
— генерируется админкой Django после установки нового приложения (INSTALLED_APPS
);request_started
,request_finished
,got_request_exception
— генерируются при обработке HTTP-запросов;template_rendered
— генерируется только в режиме тестирования приложения.
Итак сигналы *_init
, _*save
, *_delete
и post_syncdb
генерируются системой моделей Django и их можно импортировать из django.db.models.signals
.
Сигналы обработки HTTP-запросов из django.core.signals
. И тестовый template_rendered
из django.test.signals
.
А теперь реальный пример, как повесить обработчик на событие-сигнал сохранения модели. В нашем случае будет требоваться определить тип mime закачанного файла перед его сохранением в базу.
Код модели:
class MimeType(models.Model):
"""
Mime Types table
"""
name = models.CharField(max_length=200)
slug = models.SlugField()
def __unicode__(self):
return self.name
class Item(models.Model):
"""
Main file
"""
name = models.CharField(max_length=200)
slug = models.SlugField()
file = models.FileField(upload_to='files', blank=True)
mime = models.ForeignKey(MimeType, blank=True, null=True)
upload_date = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.name
def set_mime(self, mime):
obj, created = MimeType.objects.get_or_create(name=mime, slug=slugify(mime))
self.mime = obj
Посмотрите на метод set_mime
модели Item
. Он создает новый объект MimeType
или использует если он уже создан.
При этом не сохраняя модель Item
. Теперь я пишу функцию-callback, которая будет вызываться по событию сохранения модели Item
.
import mimetypes
import os.path
# init mime types dict
mimetypes.init()
def add_mime_type(instance, **kwargs):
"""
Adding mime-type to uploaded file (for future use).
Would be called on post-save.
"""
if not hasattr(instance, 'mime') or not hasattr(instance, 'file'):
raise Exception("Object %s does not have 'mime' attribute! Can't set mime-type!" % instance)
if instance.file:
extension = os.path.splitext(instance.file.path)[1].lower()
instance.set_mime(mimetypes.types_map[extension])
Итак, функция-callback add_mime_type
принимает параметр instance
, который является экземпляром модели, сгенерировавшим сигнал (в нашем случае модели Item
). Вторым параметром принимает словарь (dictionary). Кстати, это и есть один из моментов обратной несовместимости. После рефакторинга каждая функция-callback должна принимать параметр **kwargs
.
Теперь третий самый простой шаг — связывание модели с сигналом. В самом конце файла моделей добавилась строчка:
models.signals.pre_save.connect(add_mime_type, sender=Item)
Теперь перед каждым сохранением объектов Item, будет выполняться проверка и установка Mime-типа.
Кстати, я советую если у вас больше одного сигнала, выносите их в отдельный файл signals.py или можно по-старинке писать в файле моделей (что ИМХО иногда мешает чтению кода).
Почитать про сигналы можно еще в официальной доке: Django Signals и Django Built-in signal reference. Почитать про рефаторинг можно на странице Backwards Incompatible Changes и в соответствующем коммите 8223.
Александр Кошелев тоже немного раньше написал по теме, статья «А вы поймали новые сигналы?» с хорошим примером создания абстрактного сигнала.
«На сегодня все. Вопросы в студию» :-)
Django 1.0
Не буду говорить насколько релиз важен или наоборот нет. Я в целом разделаю точку зрения Ивана. Но думаю, что как раз релиз является отличным поводом написать много новых заметок, статей и примеров кода по новым и переделанным фичам.
Так что ждите в скором будущем новых статей по Django тематике. Думаю осветить подробно:
- эффективное создание форм;
- кастомизация django admin интерфейса;
- трюки с FileField и аплоадом в общем;
- сигналы в django.
Django + Spawning! 3
Вышла новая переписанная версия Spawning — WSGI сервера. Главное достоинство это non-blocking IO, т.е. большие возможности по масштабируемости (scaling).
Spawning is a wsgi server which supports multiple processes, multiple threads, non-blocking HTTP io, and automatic graceful upgrading of code.
Это очередной способ запуска django и других python-приложений для веб. Пример команды для запуска django процесса:
spawn --factory=spawning.django_factory.config_factory settings --port 9090 -s 4 -t 100
Пример для запуска приложений через paste (например Pylons используют paste для деплоя):
spawn --factory=spawning.paste_factory.config_factory development.ini
Если захотелось поставить и попробовать:
sudo easy_install Spawning
Почитайте еще обзор Эрика на английском.
Update: как ни странно товарищ Александр aka piranha практически одновременно со мной написал статью как раз про деплой через WSGI. Так что моя заметка «пролетает как фанера над Парижем», ибо мягко говоря Spawing не самый быстрый вариант :-) Читайте — Amazon byteflow: WSGI серверы кратко и юзайте fapws2.
Django newforms-admin в trunk 2
Есть! Наконец-то замержили в trunk django newforms-admin — Changeset 7967. Учтите, что после апдейта нужно будет переписывать код для работы админки. Но новость однозначно отличная! Много новых фич и ближе к релизу 1.0
Как говорят «там»: stay tuned! Будут примеры по настройке новой админки.
А товарищу Brian Rosner респект за удачный мерж.
File uploads в django 3
ДА! Это наконец-то случилось! Иван может петь победоносную песню, он так долго боролся за решение этого вопроса!
By default, if an uploaded file is smaller than 2.5 megabytes, Django will hold the entire contents of the upload in memory. This means that saving the file involves only a read from memory and a write to disk and thus is very fast. However, if an uploaded file is too large, Django will write the uploaded file to a temporary file stored in your system’s temporary directory.
Полная дока по новому аплоаду — Django | File Uploads | Django Documentation.
Google GData или Гигабаза с Гигаинтерфейсом 3
Скажу сразу: «я офигел». То, что сейчас предлагает Google для сторонних разработчиков — просто бомба. И не думайте, что App Engine это что-то новое. Да это неплохое дополнение к существуещей инфраструктуре, но самое главное внутри.
Итак, про что же я. GData — универсальный API Google для чтения, записи и поиска в его сервисах. Это очень сбалансированная смесь CRUD и Atom/RSS. Самое главное в GData — это фиды. Результаты поиска, сложные запросы, создание/обновление документов и т.п. возвращаются в формате, подобному Atom фиду. Ребята из Google практически дополнили спецификацию Atom возможностью делать запросы (выборки) и реализовали незаконченную спецификацию Atom Publishing Protocol. Другими словами гугловские сервисы видны через интерфейс GData, как фиды, которые можно читать, апдейтить, искать по каким-то параметрам и удалять. Эта модель работы с данными отлично вливается в сферу веб, что и показала практика Web2.0 (покажите популярный сайт без фида).
Какие сервисы на сегодня доступны через GData API:
- Google Docs;
- Gmail contacts;
- Notebook;
- Blogger;
- Picasa;
- Calendar;
- Base;
Полный список на сайте Google API.
Чтобы не остаться голословным хочу привести пример кода для работы с Google Docs.
import gdata.docs.service
# авторизация
gd_client = gdata.docs.service.DocsService()
gd_client.email = 'username@gmail.com' #change this
gd_client.password = '' #change this
gd_client.source = 'exampleCo-exampleApp-1'
gd_client.ProgrammaticLogin()
# запрашиваем список (фид) всех документов с сервиса
feed = gd_client.GetDocumentListFeed()
# выбираем первый документ для работы
d = feed.entry[0]
# работаем с документом
print d.title.text # выводим название документа
print d.content.src # ссылка на документ в html виде (как он хранится в google)
Для создания или изменения документа необходимо использовать python-модуль atom. Пример кода:
import atom
# устанавливаем название нового документа
document.title = atom.Title(text='my best friends')
Что еще можно добавить. Вышеприведенный код предоставлен разработчиками Google для Python. Т.е. это уже клиентская часть API. Есть также версия для Java, .NET и PHP. Так что если есть желание интегрироваться с Google, то, пожалуй, все необходимое для этого есть.
Вывод простой. Google превращается из робота индексера в датацентр для размещения информации и вычислений. На сегодняшний день — это работа с документами, почтой, контактами, блогами и фото. Все в одной среде. И новое API — это отличный вариант реализации интерфейса к фичам этого гугло-датацентра :-)
На закусь ссылка на описание протокола GData.
oEmbed или выжимка урлов 6
Сегодня, после очередного просмотра и прочтения англоязычных блогов (и фидов), обнаружил совершенно новую фичу или точнее даже формат по шарингу информации между сервисами. Интересно, что в рунете пока еще никто про это не писал. Итак, представляю oEmbed — формат для встраивания контента по URL на сторонние сайты.
Т.к. формулировка достаточно абстрактная, лучше всего приведу пример. С помощью этого формата и API я могу, имея одну лишь ссылку на страницу сайта, получить контент этой страницы в удобном для встраивания виде. От сайта-экспортера требуется поддержка формата на уровне API. Типичный пример — ссылка на YouTube ролик. Чтобы можно было при запросе на API по ссылке получить код для встраивания ролика в мою страницу.
Например, всем известный flickr поддерживает этот формат, адрес API: http://www.flickr.com/services/oembed/. Пользоваться так: http://www.flickr.com/services/oembed/?url=http://www.flickr.com/photos/dobrych/2602270116/.
Кроме flickr экспорт контента в этот формат умеют делать еще несколько сервисов. Но ничто не мешает делать свои oEmbed гейты (провайдеры) для существующих сервисов, которые еще не умеют oEmbed.
Ссылки по теме. Оригинальная новость от создателя Pownce — Leah Culver » Announcing OEmbed - An Open Standard for Embedded Content. Еще:
- приложение для django — django-oembed;
- самодельный провайдер, для сервисов, которые не поддерживают oEmbed — oohEmbed.com - your one-stop oEmbed provider.
От себя еще добавлю, что эту технологию классно использовать в так называемых tumblog-ах. Что в принципе и активно делает Pownce.
PS: если это все таки «баян», дайте знать, где еще есть инфа по теме — оч интересно.
Загрузка (upload) файлов на сервер с помощью Adobe AIR и JavaScript 1
Я давно планировал начать серию статей про фронтенд разработку, т.е. про JavaScript, CSS и HTML. Про верстку писать — уже «баян», тем более это не очень мне интересно. Так что буду стараться разбирать наиболее редкие и уникаьные примеры.
Adobe AIR — тема этой статьи. Тема не обзорная, а вполне кокретная. Итак, как сделаь загрузку файлов на сервер с помощью AIR и JavaScript. Оказалось есть нюансы, которые в документации не освещены.
Пример.
// что и куда будем заливать
var url = "http://img31.picoodle.com/upload.php";
var pictureFile = new air.File('/path/to/local.file');
// устанавливаем переменные и их значения для http запроса, как в html форме
var variables = new air.URLVariables();
variables.op = 'upload';
// настраиваем парметры http-запроса
var tmpRequest = new air.URLRequest(url);
tmpRequest.method = air.URLRequestMethod.POST;
mpRequest.contentType = 'multipart/form-data'; // это тип для загрузки файлов
tmpRequest.data = variables;
air.sendToURL(tmpRequest);
// аттач ивентов для прогресс бара и завершения загрузки
pictureFile.addEventListener(air.ProgressEvent.PROGRESS, callback_for_upload_progress);
pictureFile.addEventListener(air.DataEvent.UPLOAD_COMPLETE_DATA, callback_for_upload_finish);
// выполняем загрузку файла на сервер (отличается от простых http-запросов).
pictureFile.upload(tmpRequest, 'pic', false);
Вот про ивент air.DataEvent.UPLOAD_COMPLETE_DATA
в доке нигде не написано, я выцепил его из
примера, написанного для Flex на AcionScript. Пример рабочий, опробывал. Его нужно дополнить
хендлерами ивентов. Для примера:
function callback_for_upload_progress(event) {
var loaded = event.bytesLoaded;
var total = event.bytesTotal;
var pct = Math.ceil( ( loaded / total ) * 100 );
air.trace('Uploaded ' + pct.toString() + '%');
}
function callback_for_upload_finish(event) {
Console.log('File upload complete');
air.trace(event.data); // вывод ответа сервера на консоль air (режим отладки)
}
Эта заметка для тех, кто уже хоть немного знаком с AIR. В следующем обзоре я пожалуй напишу пример для работы с файлами. Если нужно сделать пример «с нуля» для начинающих, напишите, попробую. Хотя я считаю, что в официальной доке как раз неплохо написано с чего начать.
Я почти уверен, что у вас есть не мало вопросов по этой новой теме. Пишите в комментах, мне будет более понятно на что больше стоит обратить внимание.
Про меня 5
Решил обновить страницу автора (тобишь о себе). Делаю копи-паст в ленту. Постоянная ссылка на страницу «Об авторе».
Об авторе
Зовут меня Илья, можно по-дружески — Илюха. Позывной в сети (всякие соц. сети, мессенджеры итп) — dobrych. Так что можете смело мне писать в Gmail/GTalk на dobrych [a] gmail.com и в Skype с тем же логином.
С программированием связан профессионально уже 7 лет, но в жизни много всего интересного помимо работы. Последнее время я все больше стараюсь заниматься творчеством — фотографией и музыкой. И чаще проводить время со своей веселой семейкой. Да, кто не знает, я — счастливый муж(ик) и отец двоих уматных детишек! :-)
Мне очень нравится писать, поэтому с Сентября 2006 я — блоггер. Планирую в будующем делать новые контент-проекты, скорее всего в формате медиа-блогов. Набегами пишу в Twitter / dobrych.
Мне очень близки идеи дауншифтинга, поэтому я не спешно подыскиваю интересные варианты для миграции. Меня совершенно не устраивает ситуация в странах СНГ с неразвитостью регионов/провинции. Поэтому, буду рад любой интересной информации по теме.
Еще я пользовтель Mac (macbook pro). Это не понты и не дань моде, а просто хороший инструмент в моих руках. Делюсь опытом работы с Mac в отдельном блоге — Appleworms
Далее в перемешку.
Мне нравится:
- минимализм в дизайне;
- беспроводные устройства;
- смотреть старое кино;
- слушать инди-музыку;
- катать детей на шее;
- путешествовать;
- работать с компьютером в командной строке;
- рассказывать;
Не воспринимаю:
- снобов;
- шансон, попсу и эмо;
- виндовз.
Older posts: 1 2 3 ... 7