оптимізація і django-tagging
Взявся за оптимізацію проджекту, запустив монітор запитів і офігів, на стартовій більше 300 запитів.
А виною всього виявився django-tagging, який запускає post-init і на кожен об'єкт отримуємо + 2 додаткових запити.
Вирішується досить просто. У запит додаємо defer('tags')
django-tagging і get_by_model з логікою OR
Хороша ліба django-tagging, яка дозволяє тегувати все що завгодно. Вибірку по тегах можна зробити методом get_by_model.
TaggedItem.objects.get_by_model(Post, [u'духовність',u'культура',u'мистецтво'])і ми отримаємо об'єкти з наступними тегами але з логікою "і". Але мені потрібно такий самий метод, але з логікою "або", тобто вибрати об'єкти де зустрічається хоча би один з перелічених тегів. Мій варіант методу. Трошки говнокод, але працює. Колись може дойдуть руки навести есетичний марафєт.
def get_by_model_or(self, queryset_or_model, tags):
tags = get_tag_list(tags)
tag_count = len(tags)
if tag_count == 0:
queryset, model = get_queryset_and_model(queryset_or_model)
return model._default_manager.none()
queryset, model = get_queryset_and_model(queryset_or_model)
content_type = ContentType.objects.get_for_model(model)
opts = self.model._meta # return tagging.taggeditem
tagged_item_table = qn(opts.db_table) # `tagging_taggeditem`
where = []
where.append('%s.content_type_id = %%s' % tagged_item_table,)
or_string = "("
or_tuple = ()
params = [content_type.pk]
for i in range(len(tags)):
if i == 0:
or_string += "%s.tag_id = %%s "
else:
or_string += "OR %s.tag_id = %%s "
or_tuple += (tagged_item_table,)
params.append(tags[i].pk)
or_string += ")"
where.append(or_string % or_tuple)
where.append('%s.%s = %s.object_id' % (qn(model._meta.db_table),
qn(model._meta.pk.column),
tagged_item_table))
return queryset.extra(
tables=[opts.db_table],
where=where,
params = params
)
Django + TinyMCE + Django-tinymce-filebrowser
Як бісить, коли оупенсорсним програмістам впадло писати хоча би мінімальну документацію. Інколи доводиться курити годинами мануали.
Цей раз не виключення. Потрібно прикрутити до HTML-едітора файловий браузер (заванаження малюночків на сервер і вставка їх в документ). Одне з легеньких рішень Django-tinymce-filebrowser. Але ні слова не вказано про ініціалізацію цього аппа.
Тож:
{% block head_extra %}
<script src="{{ settings.TINYMCE_JS_URL }}" type="text/javascript"></script>
<script type="text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "advanced",
language : 'uk',
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : "True",
file_browser_callback : "mce_filebrowser"
});
function mce_filebrowser(field_name, url, type, win) {
var cmsURL = "/tinymce-fb/image";
if (cmsURL.indexOf("?") < 0) {
cmsURL = cmsURL + "?type=" + type;
}
else {
cmsURL = cmsURL + "&type=" + type;
}
tinyMCE.activeEditor.windowManager.open({
file : cmsURL,
title : 'My File Browser',
width : 420,
height : 400,
resizable : "yes",
inline : "yes",
close_previous : "no"
}, {
window : win,
input : field_name
});
}
</script>
{% endblock %}
шаблонний фільтр для числівників
Інколи потрібно разом з цифрою вказати слово у вірній множині. Наприклад: 1 коментар, 9 коментарів, 2 коментарі. Django в комплекті має багато шаблонних фільтрів, але для нашої солов'їної треба написати власний.
# -*- coding: utf-8 -*-
from django import template
register = template.Library()
@register.filter
def uapluralize(value, arg="дурак,дураки,дураків"):
args = arg.split(",")
number = abs(int(value))
a = number % 10
b = number % 100
if (a == 1) and (b != 11):
return args[0]
elif (a >= 2) and (a <= 4) and ((b < 10) or (b >= 20)):
return args[1]
else:
return args[2]
І в шаблоні:
{% load uapluralize %}
{{ m.comments_count|uapluralize:"коментар,коментарі,коментарів" }}
Посилаємо листа через Gmail
Найкращий варіант - юнікод і smtplib
GMAIL_SMTP_SERVER = 'smtp.gmail.com' GMAIL_SMTP_PORT = 587 GMAIL_USERNAME = 'gmailusername' GMAIL_PASSWORD = 'gmailpassword'
import smtplib from email import Charset from email.header import Header from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText subject = u'тестовий сабжект' sender = 'vasyl@gmail.com' recipient = 'ivan@gmail.com' from_address = u'Василь' text = u'Привіт Світ!\nВеселих свят!' Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8') multipart = MIMEMultipart('alternative') multipart['Subject'] = Header(subject.encode('utf-8'), 'UTF-8').encode() multipart['To'] = Header(recipient.encode('utf-8'), 'UTF-8').encode() multipart['From'] = Header(from_address.encode('utf-8'), 'UTF-8').encode() textpart = MIMEText(text.encode('utf-8'), 'plain', 'UTF-8') multipart.attach(textpart) session = smtplib.SMTP(settings.GMAIL_SMTP_SERVER, settings.GMAIL_SMTP_PORT) session.ehlo() session.starttls() session.ehlo() session.login(settings.GMAIL_USERNAME, settings.GMAIL_PASSWORD) session.sendmail(sender, recipient, multipart.as_string()) session.quit()
loginza + django-avatars + facebook + vkontakte
Авторизуємось через loginza, і якщо facebook нам віддає ім'я і аватар юзернейма, зберігаємо у моделі користувачів.
Для Вконтактє ситуація аналогічна, лише Вконтактє віддає малюнок з розширенням, а Фейсбук без.
def loginza_auth_handler(sender, user, identity, **kwargs):
try:
#loginza_models.UserMap.objects.get(user=user, verified=True)
map = loginza_models.UserMap.objects.get(user=user)
data = json.loads(map.identity.data)
if data['provider'] == "http://www.facebook.com/":
system_user = User.objects.get(username=user)
if data['name']['first_name']:
system_user.first_name = data['name']['first_name']
if data['name']['last_name']:
system_user.last_name = data['name']['last_name']
if data['photo']:
try:
Avatar.objects.get(user=system_user)
except:
(filename, headers) = urllib.urlretrieve(data['photo'])
img_name = '%s.jpg' % os.path.basename(filename)
copy_path = os.path.join(settings.MEDIA_ROOT, settings.AVATAR_STORAGE_DIR, system_user.username, img_name)
copy_dir = os.path.join(settings.MEDIA_ROOT, settings.AVATAR_STORAGE_DIR, system_user.username)
if not os.path.isdir(copy_path):
os.makedirs(copy_dir)
shutil.copy2(filename, copy_path)
path_ava = os.path.join(settings.AVATAR_STORAGE_DIR, system_user.username, img_name)
avatar = Avatar(
user = system_user,
primary = True,
avatar = path_ava,
)
avatar.save()
system_user.save()
auth.login(sender, user)
Для Вконтактє ситуація аналогічна, лише Вконтактє віддає малюнок з розширенням, а Фейсбук без.
Підписатися на:
Дописи (Atom)