Сигнали в Django

Простенький приклад. При створенні об'єкту моделі, необхідно в автоматично створити об'єкт в сусідній моделі.

class Task(models.Model):
name = models.CharField(max_length=120)
description = models.TextField()
price = models.CharField(max_length=5)
promotional_code = models.CharField(max_length=24)
city = models.CharField(max_length=24)
is_active = models.BooleanField(default=True)
buyer = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name

class TaskStatus(models.Model):
POSTED, ASSIGNED, COMPLETED, CLOSED = range(1,5)
TASK_STATUS_VALUES = (
(POSTED, 'Posted'),
(ASSIGNED, 'Assigned'),
(COMPLETED, 'Completed'),
(CLOSED, 'Closed'),
)
task = models.ForeignKey(Task)
task_status = models.IntegerField(choices=TASK_STATUS_VALUES, blank=True, null=True)
provider = models.ForeignKey(User, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)

def update_task_status(sender, instance, *args, **kwargs):
TaskStatus.objects.create(task=instance, task_status=1)

models.signals.post_save.connect(update_task_status, sender=Task)

fedora 14 boot screen

Дефолтова тема якась дуже страшна. Міняються теми за допомогою plymouth (який потрібно при потребі доставити)
перелік тем: /usr/share/plymouth/themes/
# plymouth-set-default-theme <назва_теми>
# cd /usr/libexec/plymouth/
# ./plymouth-update-initrd

в /etc/grub.conf ще бажано вказати ядру бажану роздільну здатність. Потестити: vbetest
моя vga=773

периферійний зір

коли сконцентровано програмую в навушниках, периферійний зір вимикається повністю.

додавання значення поля форми через перевизначення ModelForm

ситуація наступна: є форма, але передається весь комплект значень окрім task.buyer, який береться з авторизації. Перевизначаємо save, де і зберігаємо task.buyer.
views.py
@render_to('')
def tasks_add(request, template="tasks/add.html"):
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
task = form.save(request.user)
return HttpResponseRedirect('/tasks/details/%s' % task.id)
else:
form = TaskForm()

return {'form': form,}, template

forms.py
class TaskForm(ModelForm):
class Meta:
model = Task
fields = ('name', 'description', 'price',)

def save(self, user=None, commit=True):
task = super(TaskForm, self).save(commit=False)
task.buyer = user
if commit:
task.save()
return task

ініціалізація значення поля форми

для простих речей можна використати initial, наприклад, автозаповнення дати.
Тут трошки інший підхід. Ініціалізація динамічного значення форми на стадії ініціалізації ModelForm
views.py
@render_to("messages/send.html")
def message_send(request, user_id=None):
form = MessageSendForm(message_to='sdsd')
return {"form" : form}

forms.py
class MessageSendForm(forms.ModelForm):
message_to = forms.CharField(label=_("Message to"), max_length=100, required=True)

class Meta:
model = Message
fields = ('message_to','subject','text',)

def __init__(self, *args, **kwargs):
message_to = kwargs.pop('message_to',None)
super(MessageSendForm, self).__init__(*args, **kwargs)
self.fields["message_to"].initial = message_to


На виході маємо:



трошки пізніше покажу наглядний приклад використання цієї конструкції

приклад роботи з context в templatetags

register = template.Library()
@register.inclusion_tag("users/_tasks_profile.html", takes_context=True)
def tasks_profile(context):
import re
request = context['request']
if re.search('/tasks/details/\d+', request.path):
task = Task.objects.get(id = int (request.path.split('/')[3]))
user = User.objects.get(id = task.buyer_id)
return {'profile': user}
else:
return False

attachments для моделі

https://github.com/bartTC/django-attachments
Дуже класний апп!

Виключалка CSRF

settings.py
class IgnoreCsrfMiddleware(object):
def process_request(self, request):
request.csrf_processing_done = True

MIDDLEWARE_CLASSES = (
'settings.IgnoreCsrfMiddleware',
'django.contrib.csrf.middleware.CsrfMiddleware',
...
)

PyCharm

взуває NetBeans

не юзайте django-facebookconnect

Гамно, старе і глючне

глюк в django-facebookconnect

отакий глюк:
  File "../lib/facebookconnect/models.py", line 26, in 
from facebook.djangofb import Facebook,get_facebook_client
File "../lib/facebook/djangofb/__init__.py", line 490, in
require_oauth = updater(require_oauth)
File "../lib/facebook/djangofb/__init__.py", line 489, in updater
return decorator.new_wrapper(updated, f)
AttributeError: 'module' object has no attribute 'new_wrapper'


Готового вирішення так і не нагуглив. Поміг манагер:
facebook/djangofb/__init__.py
    def updater(f):
def updated(*args, **kwargs):
original = f(*args, **kwargs)
def newdecorator(view):
return updated(original(view), view)
return updated(newdecorator, original)
return updated

форма з вибірковими полями моделі

def profile_profile(request, template="users/profile.html"):
profile = request.user
REQUIRED_FIELDS = ['first_name', 'last_name', 'email',]
FormClass = forms.models.modelform_factory(Profile, fields=REQUIRED_FIELDS)
form = FormClass(instance=profile)
if request.method == "POST":
form = FormClass(request.POST, instance=profile)
if form.is_valid():
profile = form.save()
profile.save()
return {'form': form,}, template

django-registration унікальний e-mail

хороший аплікейшен, але в ньому є один баг або фіча - дозволяє реєстрацію користувачів з однаковими e-mail'ами. Лікується додаванням метода clean_email:

forms.py
from django.contrib.auth.models import User
class RegistrationForm(forms.Form):
def clean_email(self):
"""
Validate that the supplied email address is unique for the
site.

"""
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(_("This email address is already in use.\
Please supply a different email address."))
return self.cleaned_data['email']

auth_views.login після успішної логінації редіректить на /model/profile

А це реально кумарить
Лічиться додаванням в конфіг змінної:

LOGIN_REDIRECT_URL = '/'

Django Sitemap клас для Articles

### sitemap.py

from articles.models import Article

class ArticlesListSitemap(Sitemap):
changefreq = "weekly"
priority = 0.9
def lastmod(self, obj):
return obj.publish_date
def location(self, obj):
d = obj.publish_date.strftime("%Y")
return '/articles/' + d + '/' + obj.slug + '/'
def items(self):
return Article.objects.filter(is_active=True)

Модуль статтей в Django

http://pypi.python.org/pypi/django-articles/1.6a
Досить класний. Напильником працювати майже не прийшлось.

Модульне тестування

Ніколи раніше не писав тестів, але тепер відчуваю в них необхідність. Треба братись.

Django Sitemap з пустим items

Теж погано документована фіча.
Треба додати елемент в sitemap, але без прив'язки до моделі. В даному випадку це розділ "Контакти" з моделлю, але мені не потрібна індексація схованих даних.

Рішення

sitemap.py
from django.contrib.sitemaps import Sitemap

class ContactsSitemap(Sitemap):
changefreq = "weekly"
priority = 0.5
def lastmod(self, obj):
return datetime.datetime.now()
def location(self, obj):
return '/contact/'
def items(self):
return [self]


urls.py

sitemaps = {
#'flatpages': MyFlatPageSitemap,
'contact': ContactsSitemap,
}

Django FlatPageSitemap priority і changefreq

по замовчуванні FlatPageSitemap генерить лише loc, а priority і changefreq треба прописувати самому. Причому, в документації про це нічого немає, або я сліпий. Гугл теж дуже скупо описує. Танці з бубном 10 хв. і рішення знайдено.

sitemap.py

from django.contrib.sitemaps import FlatPageSitemap

class MyFlatPageSitemap(FlatPageSitemap):
def priority(self, item):
if 'about' in str(item.get_absolute_url).lower():
return 0.8
if 'clients' in str(item.get_absolute_url).lower():
return 0.3
if 'services' in str(item.get_absolute_url).lower():
return 0.8
else:
return 0.2
def changefreq(self, obj):
return "weekly"

urls.py

from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
from sitemap import *

sitemaps = {
#'flatpages': FlatPageSitemap,
'flatpages': MyFlatPageSitemap,
}

urlpatterns = patterns('',
(r'^sitemap\.xml', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
)

Гламурчик в photologue

Хороше і сире водночас jQuery рішення для photologue http://djangosnippets.org/snippets/1897/ Щоб фотки гарно гортались і слайдшоу.
Довелось підпиляти напильником як цей сніпєц, так і сам photologue, але вийшло симпатично.
Шукаємо:
{% for photo in gallery.public %}

Міняємо:
{% for photo in object.public %}


Ну і якщо не відразу зрозуміло, то пиляти треба файл шаблонів: /gallery_detail.html
А також треба позаливати в static/js всі jQuery плуги.

Теми в mc

Часто треба щось правити в mcedit, а кольори стандартні реально дістали.
Стандартні менюшки цього не дозволяють, але можна залізти в .mc/ini і підлаштувати все як потрібно.
шукаємо секцію Colors і правимо base_color
Мене ця заперла

[Colors]
base_color=lightgray,blue:normal=blue,default:selected=white,brightblue:marked=yellow,default:markselect=yellow,gray:directory=brightblue,default:executable=brightgreen,default:link=cyan,default:device=brightmagenta,default:special=lightgray,default:errors=red,default:reverse=green,default:gauge=green,default:input=white,gray:dnormal=green,gray:dfocus=brightgreen,gray:dhotnormal=cyan,gray:dhotfocus=brightcyan,gray:menu=green,default:menuhot=cyan,default:menusel=green,gray:menuhotsel=cyan,default:helpnormal=cyan,default:editnormal=green,default:editbold=blue,default:editmarked=gray,blue:stalelink=red,default





Редагувати конфіг треба іншим редактором, бо запущений mcedit перезапише конфіг на вихідний.

6 класичних SEO помилок

1. Продвижение "главной"

Не спорю, это главная страница вашего сайта, но это не значит, что вы хотите продвигать её по слову "главная". Вы же не ставите ссылку с таким анкором, когда покупаете постовые или обзоры. Так почему же на вашем сайте должна стоять такая сквозная ссылка?

Главная страница сайта должна продвигаться по тематическим ключевым словам. Например, если вы блоггер-манимейкер, поменяйте этот сквозняк в меню на слово "блог", "seo блог" или "блог о заработке".

2. Robots.txt и 301 редирект

Данная ошибка встречается гораздо чаще, чем хотелось бы, на просторах интернета. Суть её в следующем. Допустим, Яндекс определяет главным адрес с www (например, это было прописано в директиве Host в robots.txt), а потом веб-мастер установил 301 редирект в htaccess с него на адрес без www.

Приходит индексирующий робот и пытается проиндексировать сайт по адресу с www. Однако, при попытке индексации, робот перенаправляется на сайт без www при помощи серверного редиректа. Для робота это означает, что первичную страницу, с которой установлен редирект, нужно не индексировать, а заменить на страницу, на которую ведёт редирект. Продолжая попытки проиндексировать сайт, робот бегает по кругу, пока соединение не разрывается по таймауту. В результате в индексе остаётся обычно только главная страница, а на Сёрче появляется топик "Почему мой СДЛ попал под АГС?!".

3. Дублирование мета тегов

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

Да, возможно у вас сайт про оптимизацию и раскрутку сайтов в Москве, но это не значит, что такое описание должно быть у каждой страницы. Подбирайте для каждой страницы целевые ключевые слова, составляйте уникальные описания. Мета теги должны помогать уникализировать каждую страницу сайта, а не создавать дублированный контент.

4. Читать дальше

Вариаций данного словосочетания в сети довольно много: "Подробности", "Читать здесь", "Читать полностью" и т.д. Конечно, данная формулировка призывает читателя кликнуть по ссылке или перейти к более полному варианту статьи. Но поисковикам "читать дальше" мало о чём говорит.

Если у вас имеется текст "Нажмите здесь, чтобы перейти к статье 5 ошибок в SEO, которые нужно перестать допускать", сделайте анкором гиперссылки "5 ошибок в SEO, которые нужно перестать допускать". Это поможет поисковику понять, что ссылка ведёт на страницу, которая рассказывает о SEO ошибках. А вообще, старайтесь всегда правильно использовать перелинковку.

5. Прикрепил и забыл

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

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

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

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

Только в умелых руках seo-инструменты выявят проблемы и потенциальные возможности вашего сайта.

6. Нетерпеливость

Принцип "хочу всё и сразу" в SEO, увы, не работает. Вывод сайта в топ по ключевым словам это сложный и кропотливый процесс. Некоторым сайтам этот "топ" вообще не суждено увидеть.

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

Старайтесь не допускать этих 6 ошибок при оптимизации ваших веб-ресурсов!

взяв: http://seo-aspirant.ru/6-seo-mistakes

django-photologue Фото-галерея

http://code.google.com/p/django-photologue/ класний апп. Все запрацювало з першого разу. Переживаю лише щоб не було проблем на продакшені.

Caught UnicodeDecodeError while rendering: 'utf8' codec can't decode

Інколи десь символ якийсь нелюдський проскочить в шаблоні і паришся :)
Добре видно ці какахи це в mc-edit.

cpanel

Ніколи не користуйтесь простим редактором DNS-зон