среда, 26 декабря 2007 г.

Django: регистрация новых пользователей или django-registration, часть 1

Раз есть юзеры, значит, их нужно как-то регистрировать :-)

Для этого предназначен django-registration.

Работает так:

  1. юзер по адресу http://ваш_адрес/accounts/register/ заполняет форму с 4 полями: "username", "email address", "password", "password (again)".
  2. юзеру отсылается мыло с линком для активации учётной записи.
  3. юзер кликает линк, учётная запись активируется.
Чекаем код из SVN в проект, в settings.py добавляем опцию
ACCOUNT_ACTIVATION_DAYS = 3 (вместо 3 можете указать своё количество дней, в течение которых юзер может кликнуть на линк для активации), в INSTALLED_APPS добавляем 'registration',
manage.py syncdb
Можно юзать ? В принципе, да :-)

Всё ОК, и документация есть, но в версии из SVN нету шаблонов для примера. Это очень плохо. Мне пришлось прочитать документацию и код, чтобы сделать шаблоны. Чтобы вам не париться с этим, а сразу иметь рабочие примеры, я и пишу этот пост :-)

Я так настраиваю TEMPLATE_DIRS:

TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates'),
)


В каталоге шаблонов делаем подкаталог с названием registration. В нём создаём следующие шаблоны:

------ registration_form.html ------

<form action="." method="POST">
<table>
{{ form }}
</table>
<p><input type="submit" value="Submit"></p>
</form>


Необходимый элемент - {{ form }}. Это форма как раз с теми 4 полями: "username", "email address", "password", "password (again)".

------ activation_email_subject.txt ------

Your registration for {{site}}.

Содержит переменную - {{ site }} (название сайта из админки).
Это тема письма, которое будет выслано после регистрации.

------ activation_email.txt ------

Hello,

Please follow this link to complete your registration on {{ site }}:
http://www.yoursite.com/activate/{{activation_key}}/


You have {{ expiration_days }} days to complete it.


Sincerely,

bla-bla-bla


Это шаблон письма, которое будет выслано новому юзеру для подтверждения регистрации. {{ expiration_days }} задаётся в settings.py, как ACCOUNT_ACTIVATION_DAYS (у меня это 3).

------ registration_complete.html ------

<h1>Confirmation e-mail sent !<br />
Please check your inbox to complete registration :-) </h1>


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

------ activate.html ------

<h1>Confirmation e-mail sent !<br />
Please check your inbox to complete registration :-) </h1>


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


В принципе, как только вы создадите эти шаблоны, можно сразу тестировать - по адресу http://ваш_адрес/accounts/register/. После подтверждения регистрации смотрите в админке - появился новый юзер :-)

Сразу можно менять эти шаблоны под свой сайт, и юзать. Нормальный вариант !

Там ещё фичи есть, поэтому "часть 1". Наверное, ещё будут посты на эту тему, так что предусматриваю заранее :-)

четверг, 20 декабря 2007 г.

Миграции в Django

В RoR имеется концепция миграций: все изменения в моделях фиксируются определённым образом, чтобы потом можно было проапдейтить и development и production БД _автоматически_.

Django не умеет синхронизировать изменения моделей с БД (по крайней мере, на момент написания этого текста) :-(

Отсюда проблема - как быть ?

Вот так - Django Evolution.

Как юзать ?

В общем-то, элементарно. Но, имеются тонкости: если у вас ещё не было _ни одного_ syncdb с моделью, то эта система не сработает. Поэтому подключить к проекту на этапе, когда нет ни одной модели (в самом начале проекта), не получится. Я об этом упоминаю отдельно, чтобы вы не наступали на ненужные грабли.

Теперь, по шагам, для нового проекта:

1) создаём какие-то модели (модель)
2) делаем manage.py syncdb
3) забираем Django Evolution из SVN: svn checkout http://django-evolution.googlecode.com/svn/trunk/ django-evolution-read-only
4) копируем подкаталог django_evolution в свой проект (или, если есть возможность, делаем симлинк)
5) в settings.py в INSTALLED_APPS добавляем django_evolution
6) делаем новый подкаталог для всех app, которые в проекте - evolutions, в нём создаём файл "__init__.py"
7) после изменений в модели делаем manage.py syncdb, видим "Project signature has changed - an evolution is required"
8) делаем manage.py evolve --hint, видим что-то вроде этого:

#----- Evolution for website
from django_evolution.mutations import *
from django.db import models

MUTATIONS = [
DeleteField('Poll', 'pub_date')
]
#----------------------
Trial evolution successful.
Run './manage.py evolve --hint --execute' to apply evolution.

9) теперь копируем весь текст между строками с #-----, т.е. в данном случае:

from django_evolution.mutations import *
from django.db import models

MUTATIONS = [
DeleteField('Poll', 'pub_date')
]

в файл с информативным названием(в данном случае удаляется поле pub_date в модели Poll, называем delete_poll_pub_date.py) в каталог evolutions для app, в котором изменения. У меня app называется website, поэтому получается так:

/website
/evolutions
delete_poll_pub_date.py
__init__.py
не забыли создать __init__.py до этого ?

10) теперь добавляем в файл evolutions/__init__.py такую строчку:

SEQUENCE = ['delete_poll_pub_date']

т.е., в файле evolutions/__init__.py задаётся последовательность модификаций БД.

11) пишем

manage.py evolve --execute

выводится вопрос, отвечаем yes (чтобы всё проходило без вопросов, нужно добавить к команде ключ --noinput, но лучше оставить без --noinput, чтобы было похоже на Terminator 3 :-) ).

В результате имеем: Evolution successful. Т.е. прошёл апдейт структуры БД. Если ещё раз набрать manage.py evolve --execute, выведется "No evolution required."

Вот таким образом это всё работает.

Копируем на production все изменения в нашем коде, включая все файлы evolutions, и там запускаем manage.py evolve --execute.

Конечно, это не полный автомат - но согласитесь, намного лучше, чем ничего. Я думаю, что можно усовершенствовать скрипт, чтобы он сам создавал необходимое в evolutions, но самому некогда.

Насчёт багов пока не в курсе, так что про бекапы не забываем :-)
Читаем полную доку либо тут, либо в docs, который пришёл с svn.

Успехов !

пятница, 14 декабря 2007 г.

Наследование шаблонов в Django - пути.

Путь к шаблонам в теге {% extends %} _всегда_ отсчитывается от корня каталога шаблонов, определённого в TEMPLATE_DIRS.

Поэтому, морочить голову вещами типа "../../somedir/somefile" не нужно. Во-первых, это не сработает, во-вторых, можно и без "../../" :-)

Просто нужно иметь в виду, что путь начинается с корня, и всё.

Трудно забывать привычки :-)

четверг, 13 декабря 2007 г.

Происшествия Microsoft

Долго не писал, молчание - золото :-)

Никак не могу отписаться от рассылки Microsoft "Бюллетень-молния TechNet" - уже не помню, когда и зачем подписался. Но отписаться просто нереально, в отличие от других рассылок. Но не об этом сейчас.

Получил очередное сообщение, и, перед тем, как удалить, решил посмотреть, что же там пришло.

В первом же абзаце:

"...А теперь я каждый раз сталкиваюсь с проблемой, что даже простое перечисление «через запятую» наиболее интересных происшествий в области ИТ и Microsoft может по размерам выйти далеко за пределы, допустимые для одной колонки."


Ключевое слово здесь - "происшествие". Смотрим в словарь:
Событие, приключение, случай, что-н., нарушающее нормальный порядок, обычный ход вещей.
(более подробное описание под ссылкой).

Очевидно, автору хотелось иметь в виду "событие". Но, я думаю, что это оговорка по Фрейду :-)

Думаю, не нужно тут объяснять, почему рассылку с предложениями продуктов не стоит начинать текстом о собственных проблемах :-)

У Microsoft мне нравятся несколько программ, но то, как они делают многие вещи, просто удивляет, мягко говоря.

Пример хорошей, "правильной" (с моей точки зрения) компании - 37signals. Я подписан на их рассылку, но она настолько необременительна (по-моему, получил за несколько месяцев 2 письма), и настолько интересна, что стоит того, чтобы её получать.

Да здравствуют приятные события !

среда, 21 ноября 2007 г.

Ненужный логотип, часть вторая

По поводу вчерашнего логотипа - самым интересным доводом против был такой: "...сайт - это как книжка... логотип - как заголовок всей книжки...".

Итак, почему сайт - это не книжка ?

Первый вариант ответа для любого технаря: сайт не книжка, потому что это гипертекст.

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

Давайте экстраполируем понятие "книга". Книга - это вещь, во-первых. Во-вторых, есть много книг. В третьих, читая книгу, и находя в ней упоминание другой книги, необходимо физически взять в руки другую книгу, чтобы хотя бы заглянуть в неё.

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

Разве в интернете так ? Нет. Книга - это браузер. Всё, что внутри - страницы книги. Это изначальная задумка автора (авторов) гипертекста, так он и воспринимается на подсознательном уровне.

Таким образом, нагружая лишней информацией страницу книги, мы создаём для читателя проблемы. Он устаёт, хотя это и незаметно. Просто поймите, что читатель уже устал - ведь та страница, на которой он сейчас, не первая.

Если же открытая страница содержит минимум информации, и предельно ясна по сути с первой же секунды, это очень хорошо и для нас, и для читателя. Мы даём читателю момент отдыха. Это очень важно. Это расслабляет, это приятно.

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

Будьте человеками, господа программеры-дизайнеры !!

:-)

вторник, 20 ноября 2007 г.

Текстовые смайлики иногда лучше

Почему я в тексте блога не использую графические смайлики ?

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

Ненужный логотип

Сегодня работал над сайтом одного сервиса. Какой именно сервис, сказать не могу.

Мне дали макет, на основе которого нужно сделать весь сайт. Макет примерно такой:


После того, как поработал над главной страницей и "всмотрелся" в неё, дошло, что мне, как пользователю, что-то мешает. Для главной страницы я сделал вот что:



то есть, убрал логотип :-)

Тут два момента:
  1. раз дали макет, то и делать нужно на его основе
  2. макет макетом, но нужно делать так, чтобы потом не было стыдно за свою работу :-)
Поэтому, из двух зол я выбрал меньшее. Мне лучше хотя бы предложить правильный (с моей точки зрения) вариант.

Почему я считаю, что вариант без логотипа лучше ?

Компания, для которой создаётся этот сервис, не стремится с его помощью "раскрутить" свой бренд - смысл в том, чтобы заработать деньги на продукте. К тому же, у компании уже имеется большой сайт, на котором название и логотип имеются везде, где положено.

Теперь представим себе себя :-) То есть, обычного пользователя - все мы так или иначе пользователи :-)

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

Теперь с точки зрения компании-владельца сервиса.

Зашёл на сайт человек, мы хотим ему а) что-то объяснить, б) чтобы что-то продать. Зачем в этом списоке впереди а) что-то помещать ? Правильно, незачем. Потому что, когда и если ему понравится продукт, он сам с удовольствием узнает, кто его сделал.

Логично ? Логично.

Про это есть хорошая пословица - "Не ставь телегу впереди лошади." :-)

P.S.
Кстати, картинки сделал в Dia, о которой писал в предыдущем тексте :-)

Как рисовать диаграммы бесплатно

Для этого есть хорошая программа - Dia.
Много типов объектов. Фич не очень много, но рисовать диаграммы просто.
Советую :-)

понедельник, 19 ноября 2007 г.

Отправка Unicode почты из PHP

Для отправки Unicode сообщений в PHP имеется функция mb_send_mail. Она доступна, если установлено расширение mbstring.

Если mbstring по умолчанию настроен, как нужно, проблем нет - но иногда бывает по-другому :-)

Чтобы не полагаться на .htaccess и прочие внешние факторы, настроить параметры отправки лучше прямо в коде:

mb_language("uni");
mb_internal_encoding("UTF-8");


Таким образом, UTF-8 содержимое будет правильно интерпретировано mbstring.

Отправить письмо можно так:

ini_set('sendmail_from', $from);
mb_send_mail($to, $subject, $body, $from);

И $subject, и $body должны быть в UTF-8.

Предварительно можно перекодировать заголовки:

$from = 'From: "' . mb_encode_mimeheader('Петр Петрович') . '" ';

Ну, и пара линков по теме:

Unicode и PHP (julik live - на русском)

Что может неправильно работать в PHP при использовании UTF-8 (англ.)

пятница, 16 ноября 2007 г.

Ещё один никому не нужный блог :-)

Привет !

в гугле, оказывается, есть блоги - решил попробовать.

Ничего, нормально - похоже на WordPress. Не до конца приделано к гуглю, есть мелкие непродуманные моменты - но они доделают со временем, конечно.
Посмотрим, что из этого получится :-)

С уважением, Стас

P.S.
может и нужный - время покажет :-)