28 дек. 2009 г.

Django compressor и фильтры.

В прошлом посте я писал о django compressor. Не ясно было почему компрессор ничего не делает (по умолчанию) с CSS-файлами (кроме очевидного – сборки в один файл и кеширования).

Присмотревшись внимательней компрессору, удалось выяснить, что есть в нем возможность использования csstidy, jsmin, yuicompressor и google closure для сжатия css и js файлов. Однако, процесс установки и настройки этих инструментов, не так уж и прост (по крайней мере yuicompressor и google closure).

jsmin ставить отдельно не нужно. Он входит в “стандартный набор” и даже включен по умолчанию в настройках django compressor опцией


COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']


С csstidy у меня ничего не вышло. После установки csstidy на наш с Дениской debian и подключения фильтра:


COMPRESS_CSS_FILTERS = ['compressor.filters.csstidy.CSSTidyFilter']


словил 500 ошибку - фильтр не знал глобальную переменную css.


# django_compressor/compressor/filters/csstidy.py

...

17.         tmp_file.write(css)

...


YUI Compressor.

Сходил и забрал по ссылке http://yuilibrary.com/downloads/#yuicompressor.

Поставил openjdk-6-jre (советуют ставить последний, aptitude search "?provides(java-runtime)").


apt-get install openjdk-6-jre


Положил файл yuicompressor'а в /var/www/. Не спрашивайте зачем и почему – так в голову взбрело.

Добавил в settings.py моего django-проекта:


COMPRESS_JS_FILTERS = ['compressor.filters.yui.YUIJSFilter',]

COMPRESS_CSS_FILTERS = ['compressor.filters.yui.YUICSSFilter',]

COMPRESS_YUI_BINARY = 'java -jar /var/www/yuicompressor-2.4.2.jar'


Google closure пока не осилил. При, казалось бы правильных настройках:


COMPRESS_JS_FILTERS = ['compressor.filters.closure.ClosureCompilerFilter',]

COMPRESS_CSS_FILTERS = ['compressor.filters.closure.ClosureCompilerFilter',]

COMPRESS_CLOSURE_COMPILER_BINARY = 'java -jar /var/www/compiler.jar'


Попытка сжать css и js отпадает по таймауту. Возможно Вам известна причина? Напишите, я хочу сравнить производительность и результаты работы фильтров.

Возможно, кстати, кому-то удалось заставить работать csstidy?

Django compressor.

Давненько заглядывался на django-compress, но всякий раз пугался групп для css и js файлов. Дело в том, что процессе непрекращающегося deadline’а я постоянно дописываю стили в новые файлы или прям в шаблоны. Вечно потом пытаюсь разобраться в этом беспорядке, но как правило, прихожу к выводу, что некоторым стилям, или “приглашенным” js-скриптам в общем наборе делать нечего.

Пример: на сайте http://72arenda.ru/ есть форма заказа. Сейчас jquery + ui грузятся для всего сайта, но раньше было правильней – набор грузился только на странице бронирования, где эти скрипты и были востребованы. Подобных примеров в моих проектах много.

Альтернатива django-compress’у - Django compressor, использует другой подход. После подключения приложения ‘compressor’ в INSTALLED_APPS нужно прям в шаблонах заворачивать конструкции вызова или описания css или js файлов в специальные templatetag’и.

Пример с сайта:


{% load compress %}



{% compress css %}

<link rel="stylesheet" href="/media/css/one.css" type="text/css" charset="utf-8">

<style type="text/css">p { border:5px solid green;}</style>

<link rel="stylesheet" href="/media/css/two.css" type="text/css" charset="utf-8">

{% endcompress %}



{% compress js %}

<script src="/media/js/one.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript" charset="utf-8">obj.value = "value";</script>

{% endcompress %}


Django compressor заменит стили на

<link rel="stylesheet" href="/media/CACHE/css/f7c661b7a124.css" type="text/css" media="all" charset="utf-8">


а js на



<script type="text/javascript" src="/media/CACHE/js/3f33b9146e12.js" charset="utf-8"></script>


То есть, на кешированные, собранные в один файл, почищенные наборы стилей и скриптов.



UPD. Как выяснилось поздней, фильтры по умолчанию ничего не делают с содержимым файлов - не жмут, не чистят, не обфусцируют. Для активации фильтров нужно ставить yui-compressor или google closure, т.к. csstidy у меня работать отказался – жалуется, что не знает переменную css.



Compressor не делает ничего, если включен дебаг режим (DEBUG = True).



Компрессору нужен BeautifulSoup, так что проследите, чтоб он у вас был установлен.



К сожалению, пока не удалось разобраться в том, что является критерием “перестройки” кеш-файлов. В скриптах есть строка “Rebuilds the cache once a day if nothing has changed.” – Очевидно, перестройка происходит чаше, если что-то меняется (я проверял. каждый раз, когда я что-то менял, происходила “перестройка”).



Подобные инструменты нужно использовать в паре с методикам и описанными на странице http://code.google.com/p/django-compress/wiki/FarFutureExpires для достижения большего эффекта.



Успехов в освоении Django compressor и с наступающим!

Снипет для пользовательского контента в шаблонах

Очень простой и, наверняка, не слишком правильный способ вставлять html-хуки в шаблоны, содержимым которых может управлять пользователь:


# models.py:



class Snippet(models.Model):

    id          = models.AutoField(primary_key=True)

    title       = models.CharField(u'название', max_length=50)

    text        = models.TextField(u'текст', max_length=5000)

    template    = models.CharField(u'шаблон',   max_length=250, blank=True, null=True)

    def __unicode__(self): return u'%s (%s)'%(self.title, self.template)

    class Meta:

        verbose_name = u'снипет'

        verbose_name_plural = u'снипеты'



# tampletetags/realtor_tags.py:



@register.simple_tag

def get_snippet(title, **kwargs):

    from realtor.models import Snippet

    try:

        return Snippet.objects.get(title=title).text

    except:

        return u''

get_snippet.is_safe = True



# в шаблонах:



{% load realtor_tags %}



{% get_snippet 'realtor-top-left' %}


22 дек. 2009 г.

Django multiple database support - теперь поддерживает множественные соединения с базами данных

Весь твиттер буквально кипит от это новости – django теперь поддерживает множественные соединения с базами данных. Фича влита в транк и описана в документации.

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


# in settings.py:



DATABASES = {

    'default': {

        'NAME''app_data',

        'BACKEND''django.db.backends.postgres_psycopg2',

        'USER''postgres_user',

        'PASSWORD''s3krit'

    },

    'users': {

        'NAME''user_data',

        'BACKEND''django.db.backends.mysql',

        'USER''mysql_user',

        'PASSWORD''priv4te'

    }

}



# in model lookups:



Author.objects.using('default').all()



# using('default') - явное указание БД для запроса. Если не указывать будет браться default


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

UPD. Этот пост как-то “сам собой” залез на хабр, и теперь собирает заслуженную (и не только) критику.

20 дек. 2009 г.

Django CMS – show_menu

UPD: Начиная с версии 2.1.0 beta загрузка меню тэгов происходит по новому (см. http://www.django-cms.org/news/2010/03/24/django-cms-210-beta-released/).

Сегодня попытаюсь рассказать о template tag’е show_menu в django-cms. Сам разбирался с ним методом научного тыка.

{% show_menu %}


Тэг генерирует меню навигации для текущей (выбранной, открытой) страницы.

Параметры

Show_menu принимает следующие необязательные параметры:
start_level - начальный уровень навигации,
end_level конечный уровень навигации,
extra_inactive – начальный уровень “дополнительной” навигации,
extra_active - конечный уровень “дополнительной” навигации
“Дополнительная” - это навигация по страницам, которые не являются прямыми потомками и предками текущей страницы.
Для этого тэга можно переопределить шаблон вывода, создав в шаблонах своего проекта свой шаблон cms/menu.html или передав в ещё один дополнительный параметр template. Пример:

{% show_menu 0 100 0 100 "my_new_cool_menu.html" %}


Играемся с уровнями навигации

Для тестирования работы тэга возьмем сайт-пример demo.concepter.ru, о котором я уже писал раньше. (UPD: сайта demo.concepter.ru больше нет). Итак, имеет исходное дерево сайта:
  • root 1
    • 1 level child (p, n)
      • 2 level child (p, n) of 1
      • 2 level child (p) of 1
    • 1 level child (p)
      • 2 level child (p, n) of 1 level child (p)
    • 1 level child
    • 1 level child (n)
  • root 2
    • 1 level child (p, n) of root 2
      • 2 level child (p, n) of 1 of root 2
    • 1 level child (p) of root 2
буквы в скобках – статусы. p – страница опубликована, n – “в навигации”.
На главной странице вызваны show_menu со следующими параметрами:

1. {% show_menu 0 100 100 100 %} - Вся навигация



2. {% show_menu 0 100 0 100 %} - Навигация по активному дереву



3. {% show_menu 0 100 0 1 %} - Навигация с одним дополнительным уровнем



4. {% show_menu 0 0 0 0 %} - Корневая навигация



5. {% show_menu 1 1 100 100 %} - Навигация первого уровня



6. {% show_menu 1 1 0 100 %} - Навигация по первому уровню (только активное дерево)



7. {% show_menu 0 1 100 100 %} - Навигация по перевому и второму уровню


Под активным деревом в данном случае понимаем дерево, в которое входит выбранная страница. Например, потомков root 1 активным деревом будет все, что ниже root 1 и root 1, включительно.

Независимые от активной страницы блоки навигации

Естественно, что вся навигация (1), корневая навигация (4), навигация первого уровня (5) и навигация 0-1 уровней (7) не будут меняться с изменением активной страницы (т.е. при переходе на новую страницу). Потому сразу покажу, как они выглядят для всех страниц:

Complete navigation

Level 0 navigation

Level 1 navigation

Level 0-1 navigation

Навигацию по активному дереву


{% show_menu 0 100 0 100 %}


Далее посмотрим какие страницы попадут в навигацию по активному дереву в зависимости от смены страницы.
1. root 1
2. root 2
Активное дерево развернуто, а не активное – нет. В навигации все страницы с параметрами страница “опубликована” и “в навигации”.

Навигация с одним дополнительным уровнем


{% show_menu 0 100 0 1 %}


1. root 1
2. root 2
3. 1 level child (p, n)
4. 1 level child (p, n) of root 2
В навигации есть все, что опубликовано и одновременно присутствует в навигации. Тэг честно вываливает 1 дополнительный уровень к текущей странице (потомки).

Навигация по первому уровню (только активное дерево)


{% show_menu 1 1 0 100 %}


Такой тип навигации можно использовать в паре с навигацией 0-го уровня для генерации двухуровневого меню на главной странице, как тут:
image
image
Естественно, там сделано не так, но для примера подойдет.
Далее пары “Активная страница” + содержимое навигации:
root 1 + 1 level child (p, n)
root 2 + 1 level child (p, n) of root 2
1 level child (p, n) + 1 level child (p, n)
2 level child (p, n) of 1 + 1 level child (p, n)
1 level child (p, n) of root 2 + 1 level child (p, n) of root 2
2 level child (p, n) of 1 of root 2 + 1 level child (p, n) of root 2
Очевидно, что в навигации данного типа меню присутствует первый уровень активного дерева. Как всегда, в неё попали только опубликованные страницы со статусом “в навигации”.

Резюме

С помощью данного тэга можно выстраивать навигацию любой сложности и вложенности, главное не запутаться в уровнях и активных деревьях.
Без параметров тэг инициализируется с 0 100 и 0 100, так что в некоторых случаях можно использовать просто {% show_menu %}.
Помимо show_menu в django-cms есть ещё show_menu_below_id, show_sub_menu и show_breadcrumb, использование которых может существенно сэкономить время и нервы. Хотя, какие там нервы? Django-cms – полнеищий fun.
Читайте все тоже самое, но на английском на странице http://www.django-cms.org/en/documentation/2.0/navigation/.

14 дек. 2009 г.

При не одном заполнении всех полей и соответственно правильном

Как правильно писать в тех. поддержку? Как правильно задавать вопросы? – все это вопросы не для обычного пользователя. В сущности, обычному пользователю все равно как это делать правильно. Такие знания нужны людям так, или иначе связанным с производством информационных систем, АРМ и многих других страшных слови аббревиатур. Обычный пользователь привык к мысли о том, что когнитивный разрыв между его пониманием систем, и пониманием систем программистом на столько велик, что программист скорей бог и экстрасенс, чем обычный человек. Зачем с богами разговаривать обычным языком? Ан нет - не боги горшки обжигают.

Сегодня на адрес тех. поддержки одного из наших проектов пришло письмо следующего содержания:

“День добрый,при не одном заполнении всех полей и соответственно правильном,невозможно пройти регистрацию,возможно с Вашем сайтом какие-то неполадки?”

У меня по русскому тройка, поэтому я не буду (не в праве) судить человека написавшего это. Да и не люблю я, когда люди начинают друг другу объяснять где запятые ставит, если суть ясна. Но в данном случае суть ускользает (от меня, по крайней мере).

Версия Дениса:

“человек как только не е***ся, заполняя поля, но так и не смог подобрать такую комбинацию, которая позволила бы ему зарегистрироваться.”

Вы что думаете? Случалось Вам получать подобные письма?

11 дек. 2009 г.

Django RSS для Яндекс новостей

Не секрет, что контриб syndication в django умеет делать RSS ленты, и делает это очень правильно. Но вот беда, Яндексу для его новостей нужны не просто RSS 2.0 ленты, а RSS 2.0 с добавлением тэга yandex:full-text, да ещё и в кодировке windows-1251.

Завелосипедить эту досадную оплошность можно следующим образом (естественно, не только им, но именно в споре рождается истина, так что жду комментарии):


# in urls:

   (r'^yandex.xml$''text.views.yandex_rss'),





# in views:



def yandex_rss(request):

    from news.models import New

    output = {

        'news': New.objects.filter(rubrics__pk=11).order_by('-published').select_related()[:15],

    }

    from django.template.loader import render_to_string

    rendered = render_to_string('yandex.html', output).encode('cp1251')

    return HttpResponse(rendered, mimetype='application/rss+xml; Charset=windows-1251')



# yandex.html:



<?xml version="1.0" encoding="windows-1251"?>

<rss version="2.0"

     xmlns="http://backend.userland.com/rss2"

     xmlns:yandex="http://news.yandex.ru">

    <channel>

        <title>вИшиме.ру</title>

        <link>http://vishime.ru/</link>

        <description>Последние новости с вИшиме.ру</description>

        <lastBuildDate>{% now "r" %}</lastBuildDate>

        <image>

            <url>http://vishime.ru/media/favicon.ico</url>

            <title>вИшиме.ру</title>

            <link>http://vishime.ru/</link>

        </image>

        {% for new in news %}

        <item>

            <title>{{ new.title }}</title>

            <link>http://vishime.ru{{ new.get_absolute_url }}</link>

            <description>{% if new.lead %}{{ new.lead|striptags|safe }}{% else %}{{ new.text.text|striptags|truncatewords:"20"|safe}}{% endif %}</description>

            <author>{% if new.author %}{{ new.author }}{% else %}вИшиме.ру{% endif %}</author>

            <category>{{ new.rubrics.get }}</category>

            <pubDate>{{ new.published|date:'r' }}</pubDate>

            <yandex:full-text>{{ new.text.text|striptags|safe }}</yandex:full-text>

        </item>

        {% endfor %}

    </channel>

</rss>


Пример с вИшиме.ру, но внимание (!), эту ленту ещё не приняли в яндекс новости, так что приведенные куски кода ничего не гарантируют.

Ещё раз, я понимаю, что нужно такие вещи писать по другому (раз уж есть syndication).

7 дек. 2009 г.

Мороз. Можно в школу не ходить?

Вчера сын не учился - из-за низкой температуры занятия для младших классов отменили. Я не слушаю радио, а в интернете информацию по данному вопросу мне найти не удалось. Дмитрий говорил, что ему нужна подобная функциональность на вИшиме.ру.
В итоге, из за всех этих факторов, а также нездорового любопытства, за пол часа наклепал ерунду, которой можно пользоваться для проверки сабжа.
Данные берутся из гисметео (только Тюмень), а правила отмены занятий взяты из статьи http://www.t-i.ru/article/8745/. Скрипт простой как мычание:

# -*- coding: utf-8 -*-

from django.shortcuts import render_to_response

from django.template import RequestContext

from django.utils import http

from datetime import datetime

import xml.etree.ElementTree as ET



def average(numbers):

    return sum(numbers) / len(numbers)



class Forecast(object):

    datetime = datetime(2009, 12, 7, 20)

    pressure_max = pressure_min = temperature_max = temperature_min = wind_max = \

    wind_direction = wind_min = relwet_max = relwet_min = heat_max = \

    heat_min = 0

    def avg(self):

        return average([self.temperature_max, self.temperature_min]), \

            average([self.wind_max, self.wind_min])

    def npu_1_4(self):

        '''

        Занятия для учеников 1-4-х классов отменяются, если температура воздуха

        опускается до -30 С и ниже при скорости ветра менее 2 метров в секунду.

        При скорости ветра 2 метра в секунду и более занятия отменяют уже при

        -25 градусах.

        '''


        avg_temp, avg_wind = self.avg()

        return (avg_wind >= 2 and avg_temp <= -25) or (avg_wind < 2 and avg_temp <= -30)



    def npu_1_9(self):

        '''

        Школьники 1-9-х классов могут остаться дома, если столбик термометра

        показывает -35 градусов и ниже, при этом скорость ветра должна быть

        менее 2 метров в секунду. А при большей его скорости занятия для

        учеников отменяются и при температуре -30 и ниже.

        '''


        avg_temp, avg_wind = self.avg()

        return (avg_wind >= 2 and avg_temp <= -30) or (avg_wind < 2 and avg_temp <= -35)

    def npu(self):

        '''

        Занятия отменяются по всей школе (1-11-е классы) при температуре

        наружного воздуха -40 градусов и ниже (при этом скорость ветра не должна

        превышать 2 метров в секунду).

        ??? превышать ??? - наверное, должна быть не меньше.

        '''


        avg_temp, avg_wind = self.avg()

        return (avg_wind >= 2 and avg_temp <= -40)



def index(request):

    h = http.urllib.urlopen('http://informer.gismeteo.ru/xml/28367_1.xml')

    xml = h.read()

    tree = ET.XML(xml)

    res = []

    for f in tree.getiterator('FORECAST'):

        obj = Forecast()

        obj.date = datetime(

            int(f.get('year')), int(f.get('month')), int(f.get('day')),

            int(f.get('hour'))

        )

        for x in f.getchildren():

            for y in x.items():

                setattr(obj, str(x.tag.lower())+'_'+y[0], int(y[1]))

        res.append(obj)

    output = {

        'res': res,

    }

    return render_to_response('index.html', output, context_instance=RequestContext(request))



Посмотреть результат можно тут: school.concepter.ru. Он не причесан и не информативен, но с функцией справляется – если занятий нет, он напишет.

UPD. Спасибо Земе за ликбез.

UPD2: Нужно смотреть не температуру (temperature_min и temperature_max), а температуру комфорта (heat_min и heat_max) – отменяют по ней.

Заочная встреча с создателем вИшиме.ru

Позавчера (в субботу) прокладывали ethernet-кабели в новом офисе ИГС. Из-за разных неожиданных мелочей провозились на 1.5 часа больше, чем я планировал. Не страшно, но в 15 часов ко мней домой приезжал Дмитрий Орлецкий - автор перспективного проекта о городе Ишиме - вИшиме.ru. Так уж вышло, что я в этом проекте тоже участвую.
Встретится у нас так и не получилось, но на мою жену он произвел положительное впечатление, что само по себе уже очень хорошо. Новое время стирает привычные границы. Раньше я не мог себе представить, что буду работать с каким-нибудь человеком 2 месяца, получать от него деньги, и не видеть его "в живую". Теперь - обычное дело.
вИшиме.ru написан на django и использует несколько весьма популярных pluggble апликух. Если хотите, я могу описать его архитектуру подробней, может быть даже выложу некоторые куски кода. Хотите?

Щедрый-мудрый Google или "1400 руб. на рекламу Вашего сайта в Google" от Google Apps

Всем привет!
Так уж вышло, что я пользуюсь Google Apps очень активно. Почти всем новым клиентам/друзьям и сотрудникам с собственными доменными именами я рекомендую завести аккаунт в Google Apps. При том я понимаю, что Google будет "владеть" информацией в почте и документах моих друзей, но по факту, стоимость владения таким решением перекрывает все эти призрачные недостатки.

Щедрый
Несколько дней назад Google решил вознаградить меня за пропаганду - прислал целых 6 купонов (видимо, по кол-ву зарегистрированных лично на меня Google Apps доменов) на рекламу сайта в Google AdWords.

Мудрый
Рекламные купоны Google рассылает почти всем, кто потенциально может быть связан с веб-мастерингом и рекламой в интернете. Естественно, Вы не можете просто взять 1400, которые Вам подарили, более того, их нельзя даже просто пустить в рекламу - нужно вложить немного своих денег, чтоб начать использовать купоны. Аккаунт, на котором будет использоваться купон должен быть младше 15 дней, что намекает на механизмы в Google, похожие на приемы работы советских чиновников - поднять кол-во рекламодателей за счет явно не новых пользователей сервиса. Но определенно, польза Googl'у от этого мероприятия есть - до письма я вообще не планировал рекламироваться, а теперь озабочен на столько, что ищу способы пристроить купоны даже тут, у себя в блоге. Видимо, сработали глубинные подсознательные русские механизмы поиска халявы.

Минус в том, что я не успею использовать их все до 31.12.2009. Может их продать? Или подарить кому-нибудь? Пишите в комменты, как мне поступить!


5 дек. 2009 г.

Завидная лаконичность


На сайте компании-клиента только что посетитель оставил удивительно лаконичный отзыв. Попробуйте произнести в слух на одном выдохе написанное, и Вам сразу станет весело и легко.

1 дек. 2009 г.

Тест для фриланс-работодателя

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

Мини-тест для работодателя:

Мне нужна:

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

Работа должна выполнятся:

  • в срок,
  • качественно,
  • так, как договорились.

Связь с работником:

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

* Между последними двумя ответами есть разница.

Итак, думаю если работодатель адекватен, или хотя бы претендует на адекватность, будет выбирать последние пункты. Почему? Потому что между работником и работодателем в здоровой обстановке должны быть трудовые/товарно-денежные отношения. Работодатель покупает часть жизни работника и платить ему за это компенсацию. При это он не покупает человека целиком, т.к. реальная стоимость даже ничего не умеющего нищеброда чрезвычайно высока.

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

Любовь за деньги не купишь, согласны? Тогда почему работодатель уверен, что если он будет хорошо платить своему работнику, то последний будет его за это любить? Бред. Дистанция, уважение, возможность реализовать свои таланты, помогут работодателю “влюбить” в себя работника (премии путь тоже остаются :) ).

28 нояб. 2009 г.

Священник Иоанн Охлобыстин о своей роли в фильме Царь (и не только о ней)

Давно уже Интернет превратился в среду обмена частными мнениями. Причитать “отзыв” какого-нибудь молодого критика в Интернете даже проще, чем порнуху посмотреть (а казалось бы?). Почему? Да все потому же – людям хочется, видимо, “обратной связи”, общения. И желательно, чтоб не просто обмениваться мнениями, а побольше говорить. Чтоб слушали/читали. Чтоб всем показать, что ты тоже парень умный…

Вот и у меня в блоге хватает таких “рецензии”: http://markeev.labwr.ru/search/label/видео, и далеко не все лестные.

А вот прочесть мнение того, кого критикуют, удается не часто. Мне было  интересно прочесть мнение Ивана Охлобыстина о его роли в фильме Царь и о критике в его адрес.

Прочтите! Советую.

26 нояб. 2009 г.

Ситуация с Many-to-Many в django

На днях контрибуторы django что-то там поменяли с сырыми sql-запросами для Many-to-Many полей. Это было сделано для поддержки нескольких баз и повышения какой-то там безопасности (видимо, при удалении связанных элементов удалялось что-то лишнее).

В общем, одно можно сказать точно: в документации к Many-to-Many полям появились такие строки:


  1051 Working with Many-to-Many Models 

  1052 -------------------------------- 

  1053  

  1054 By default, admin widgets for many-to-many relations will be displayed 

  1055 on whichever model contains the actual reference to the ``ManyToManyField``. 

  1056 Depending on your ``ModelAdmin`` definition, each many-to-many field in your 

  1057 model will be represented by a standard HTML ``<select multiple>``, a 

  1058 horizontal or vertical filteror a ``raw_id_admin`` widget. However, it is 

  1059 also possible to to replace these widgets with inlines. 

  1060  

  1061 Suppose we have the following models:: 

  1062  

  1063     class Person(models.Model): 

  1064         name = models.CharField(max_length=128

  1065  

  1066     class Group(models.Model): 

  1067         name = models.CharField(max_length=128

  1068         members = models.ManyToManyField(Person, related_name='groups'

  1069  

  1070 If you want to display many-to-many relations using an inline, you can do 

  1071 so by defining an ``InlineModelAdmin`` object for the relationship. 

  1072  

  1073     class MembershipInline(admin.TabularInline): 

  1074         model = Group.members.through 

  1075  

  1076     class PersonAdmin(admin.ModelAdmin): 

  1077         inlines = [ 

  1078             MembershipInline, 

  1079         ] 

  1080  

  1081     class GroupAdmin(admin.ModelAdmin): 

  1082         inlines = [ 

  1083             MembershipInline, 

  1084         ] 

  1085         exclude = ('members',) 

  1086  

  1087 There are two features worth noting in this example. 

  1088  

  1089 Firstly - the ``MembershipInline`` class references ``Group.members.through``. 

  1090 The ``through`` attribute is a reference to the model that manages the 

  1091 many-to-many relation. This model is automatically created by Django when you 

  1092 define a many-to-many field. 

  1093  

  1094 Secondly, the ``GroupAdmin`` must manually exclude the ``members`` field. 

  1095 Django displays an admin widget for a many-to-many field on the model that 

  1096 defines the relation (in this case, ``Group``). If you want to use an inline 

  1097 model to represent the many-to-many relationship, you must tell Django's admin 

  1098 to *not* display this widget - otherwise you will end up with two widgets on 

  1099 your admin page for managing the relation. 

  1100  

  1101 In all other respects, the ``InlineModelAdmin`` is exactly the same as any 

  1102 other. You can customize the appearance using any of the normal 

  1103 ``InlineModelAdmin`` properties. 


Суть: теперь у нас есть новая возможность, сделать inline (модель в модели, в админке) редактирование самизнаетекаких полей. Сие – благо. В цмске для посуточной аренды у меня до сих пор вылазят какие-то проблемы с виджетом для списка сайтов (связанных со страницами).

25 нояб. 2009 г.

Orb and the Oracle на технологическом дне Oracle в Тюмени?

Сегодня заметил ещё одну фишку в новостях Нефтегаза. Т.к. там часто все меняют, а потом говорят, что так и было прилагаю скрины.

Сперва сама новость:

oracle

Теперь собственно картинка к новости, которая доставляет:

image

На сколько я понимаю, это скрин или обои из игры Orb and the Oracle. Какое отношение эта игра имеет к технологическому дню Oracle,компании Oracle и/или аспирантам кафедры "Геоинформатика"  известно, наверное, только Скурихиной Юлии Валерьевне…

А ещё, удивительно, но факт – судя по фону, у Нефтегаза весна.

19 нояб. 2009 г.

Планета 51 и Гэри Олдман

planeta51

Сегодня ходили на мультик “Планета 51”. Мульт отличный, давно не было ничего подобного.

Хотелось бы отметить тот факт, что мужика с внешностью Шварцнейгера (он реально похож, на фото вверху он справа) в англ. версии озвучивал не губернатор Калифорнии, а любимый оллдеевцами Гэри Олдман.

Зачем Гуглы и Яндексы борются за "чистоту" поисковой выдачи?

Далее не фильтрованный поток сознания, спровоцированный 20–ю невыполненными заданиями по оптимизации сайта и литром tuborg greenfest.

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

Зачем люди стремятся вывести в топ поисковиков свои сайты? Глупый, конечно, вопрос, но в наше время иметь сайт в интернет - уже не гарантия привлечения клиентов, и всемирной известности. Скорей наоборот, если вы сделали сайт своего агентства недвижимости, или интернет магазина бытовой техники - у вас нет никаких шансов на привлечение дополнительных клиентов. Даже "региональная привязка" не поможет, если вы конечно, не в исландии торгуете. В любом случае, в любой конкурентной среде, а интернет - это очень конкурентная среда, нужно продвижение.

Реклама в интернете теперь нужна также, как информация о объектах недвижимости на рынке аренды оной. Агентства недвижимости в свое время также “построили” свой рынок. Информация сперва была труднодоступна - риэлторы помогали её находить (прям как поисковики) и доводить до нужных людей за определенное вознаграждение. Но затем что-то неуловимо изменилось - альтернатива работе с агентствами недвижимости исчезла - осталась только свобода слова и средства массовой информации засранные агентствами на столько, что любой частник, решивший обойтись своими силами только зря потратит время. Может быть причиной тому послужит разовый характер его деятельности, а может сдерживание информации - и есть бизнес нового тысячелетия.

Но вернемся к теме. Поисковики автоматически продвигают только уникальный контент. Что это значит для обывателя? Значит, что если вы продаете в городе Х, мобильные телефоны вам не следует смотреть на интернет, как на дешевый и выгодный способ рекламы. Забудьте об интернете. Намного выгодней для вас будет купить цветной лазеный принтер и 3 набора картриждей к нему, а затем заполонить город Х своими листовками. Интернет - инструмент глобальной рекламы и уникального контента. Если у вас нет интереса к глобальному рынку, а уникальная у вас - только уверенность в себе - забудьте про интернет как средство улучшения бизнес показателей. Для вас интернет будет источником не ясных расходов...

И с позиции клиента – если вы ищите мобильный телефон марки Y в городе X, поисковики предложат вам полный перечень магазинов из default city с невероятно разнообразным прайсом и набором фенек, а вот магазин на углу улиц Ленина и Пердыщенко в выдачу не попадет, не смотря на то, что Агонасян Д.М. (владелец магазина) 3 месяца назад сделал сайт, выложил на него весь перечень моделей и прайс.

Интернет, по сути - новое пространство для рекламы. Если реклама креативна - она работает. Говоря языком поисковиков: материал либо уникален (креативен), либо оплачен (контекстная реклама), иначе он не нужен нашему пользователю. Пользователь его не хотел.

А что это за “хотел” такой? Кто определяет "угодоность" пользователю? Откуда она взялась?

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

которые писал в документах с низкочастотными запросами (НЧ) слова из высокочастотных запросов (ВЧ) для привлечения посетителей. "Порно, сиски, проститутки, реальное видео, подсмотреть" в документе о фирме продающей принтеры. WTF?

В те золотые времена написав у себя на сайте “золотой дождь” или “из попки в ротик” можно было получить много-много посетителей.

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

Ну да ладно, давайте тогда считать полезность ресурса?

Много внешних ссылок на ресурс, значит ресурс очень востребован и цитируем.

Высокое кол-во внешних ссылок на страницу, на мой взгляд свидетельствует о высокой социальной адаптивности создателей сайта, и далеко не всегда о его полезности и уникальности. Но поисковики тогда думали иначе, кроме того, тогда небыло никакой социальзиции и веб 3.0 (это ещё что за х**ня?).

Считаем кол-во ссылок, присваиваем этому параметру крутое название и можно открывать собственную фирму-поисковик.

Поисковая машина “Ачерядь”. Измеряет Очередь Документа в Релевантном Списке (ОДРС).

Теперь этого мало. Нужно оценить полезность каждого источника внешней ссылки. А как же ссылки за которые не отвечает вебмастер? Ведь, если учитывать полезность каждой внешней ссылки, то можно запросто расправиться со своими конкурентами, наделав некачественных ссылок с говно-ресурсов. Оказывается, Пейджи с Воложами и об этом подумали. Сайт пессемизируется только за внутренние факторы (все, что на сайте), а за внешние его можно только похвалить - так они говорят, но это не правда. Я проверял. В самом начале раскрутки одно сайта я прогнал его по каталогам. Как раз тогда начиналась охота на линкопомойки и в итоге сайт не только не подрос, но и потерял 20 единиц тИЦ'а.

Зачем поисковики постоянно совершенствуют механизмы ранжирования и выдачи? Зачем нужно так старательно и усердно бороться за качество выдачи? Думаю, если появится какая-то любая серебряная пуля в области SEO - все тут же перестанут тратить деньги на контекстную рекламу.

Поэтому, как и водится, серебряной пули нет :).

Что же нам тогда остается, если все способы продвижения рано или поздно канут в лету? Есть несколько способов продвигать ресурсы, бороться с которыми поисковики пока не научились (или я об этом пока не знаю):

- продвижение статьями (1)
- дорвеи (2)
- уникальные идеи (3).

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

2 - псевдо уникальный контент, существующий с единой целью - перенаправления на сайт-цель. Прелесть метода только в его автоматичности.

3. Даже писать об этом не хочется, т.к. на них то как раз не хватает времени.

Я не верю в биржи продажи ссылок, постинг в каталоги и социальные закладки.

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

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

Хорошая выдача должна быть важна для клиентов поисковых систем, которые покупают контекстную рекламу. Разве? А зачем человеку, купившему спец размещение в яндексе по слову "аренда квартир посуточно в Крыжополе" за 3 тысячи в месяц более релевантные объявления в естественной выдаче? Ему клиенты нужны, а не релевантная выдача.

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

13 нояб. 2009 г.

Всё о Тюмени – агрегатор новостей

Вчера, потехи ради, запустил Агрегатор новостей о Тюмени.

Цель: посмотреть на поведение поисковиков по отношению к копированному контенту.

Я уже замечал, что google не охотно индексирует сайты с контентом похожим на уже отсканированный, но в случае с подобными этому сайтами блокада ресурса может вообще никогда не пройти - прошлый эксперимент закончился тем, что по прошествии 2 месяцев в гугле так и не было ни одной страницы с сайта.

Посмотрим, чем все кончится на этот раз…

Perfect10.ru – ворох женщинофф.

По работе задействован в проекте http://perfect10.ru/ - международный интернет-конкурс красоты. Проект сделан на django.

Заказчики не ждали большого количества посетителей, но на днях обнаружилось, что конкурс весьма и весьма востребован. Каждый день регистрируется не менее 5 новых участниц (и даже один участник уже был).

Интересного с точки зрения django в проекте – платные сервисы сделанные при помощи smscoin.

Сейчас доделываю инструмент для рассылки сообщений участницам. Вызываться он будет по крону (management command) и срабатывать по определенному правилу. Например, если в анкете нет фотографии, то раз в день участнице будет отправляться письмо с просьбой добавить фото (наверное, ограниченное количество раз, а затем анкета будет удалятся).

Конечно, у сайт ещё масса недочетов – нет настроек для главного фотографии участницы (портретные фото есть, оказывается, не у всех); карта сайта обещана, но пока не сделана; голосование оформлено в виде ссылок, а не форм (в итоге, первое время поисковые боты постоянно дергали ссылки рейтингов); анонимный рейтинг не так уж и сложно накрутить и прочее...

1 нояб. 2009 г.

Динамика популярности слов связанных с арендой недвижимости в Тюмени

Точней, к сожалению, не получается – слишком мало данных по региону. В России можно точней, но там, почему-то “гостиницы” значительно популярней “квартир”.

РуХата - Снять или Сдать без посредников

Дело Тимура и его команды живо :). Очередная реализация популярной в последнее время идеи для стартапа об аренде без посредников.

  1. Я не имею наималейшего отношения к авторам и владельцам данного проекта
  2. Эта реализация идеи не то чтобы хорошая, она вообще никакая
  3. Для Тюмени это проект не подходить – google карт нет.

Но прямую ссылку с блога данный ресурс я публикую потому, что мне кажется должны быть сервисы подобные этому. Возможно, после 20-го или 30-го такого проекта появиться какой-нибудь прообраз, набор правил для таких проектов. Затем, возможно, некоторые из них начнут реально работать и помогать людям.

28 окт. 2009 г.

Django: AutoComplete widget.

Год назад я писал о виджете авто дополнения ввода. Тогда я везде старался использовать YUI. Сегодня столкнулся с необходимостью снова прикручивать подобный виджет, но использовать YUI ещё раз мне ужасно не хочется. Нужно будет тащить за ним несколько js файлов, в которых я мало что понимаю (dependency configurator особо не добавляет понимания), кроме того, наверняка есть другие более изящные решения.

Ну во-первых, на djangosnippets.org есть примеры jQuery Autocomplete и YUI Autocomplete (о котором я ничего не знал, когда писал свой вариант), есть и другие: http://www.djangosnippets.org/tags/autocomplete/.

Во-вторых, есть wiki-страница на djangoproject.com AutoCompleteSolutions, на которой перечислено несколько решений данной проблемы. Особо радует дата появления последней ссылки - 2009-09-15. Здесь же есть ссылка на первый YUI-Django-AutoComplete 2006 года (я тогда про django в принципе ничего не слышал).

После просмотра большей части вариантов я остановился на http://bitbucket.org/tyrion/django-autocomplete/, так как виджет в данном случае останется сторонним приложением, которому не нужно будет прописывать отдельные view для получения каждой новой порции данных. Здесь используются конструкции вида:


...

from autocomplete.views import autocomplete





autocomplete.register('user', User.objects.all(), ('username''email'), 5)

autocomplete.register('name', User.objects.all(), ('username',), 5'username''username')



urlpatterns = patterns('',

    url('^autocomplete/(\w+)/$', autocomplete, name='autocomplete'),

    ...


Ещё плюс – в media папке приложения есть jquery и YUI, что как бы намекает на возможность использования и того и другого – мелочь, но приятно (вдруг решу что-то поменять в старых проектах).

По тем же критериям (кроме поддержки YUI), но более новый вариант решения http://code.google.com/p/django-autocomplete/.