Не секрет, что в разработке Django-приложений нет ничего особенного. Точнее, не требуется ничего лишнего. Django - это Python. Значит, нужен текстовый редактор и консоль. И конечно же браузер - но это уже для тестирования. Но для того, чтобы писать было удобно, нужно IDE. Или продвинутый редактор. Emacs - очень продвинутый редактор ;)

Вот так выглядит мой Emacs - ничего лишнего, все нужное. Проверка синтаксиса делается с помощью Flymake + pyflakes (или pylint, pychecker), но не это главное. То, о чем я хочу рассказать - это сниппеты. Как? Легко.

Yasnippet - это оно. Ставить надо полную версию, а не bundle, который в одном файле. Но там же нету сниппетов для Django! Не вопрос - я все сделал. bzr branch lp:django-mode, читаем README, делаем и наслаждаемся. В комплекте еще режим для шаблонов и функции для вставки i18n тегов (C-c C-t в питоновом коде "_(%выделенное%)", в html-шаблонах "{% trans "%выделенное%" %}").

А можно еще скачать мой конфиг (Yasnippet в комплекте же). Короче, чтобы меньше всего париться и получить готовый IDE:

sudo port install tidy # или apt-get, если на Debian/Ubuntu. У меня OS X ;)
sudo pip install pyflakes # easy_install - уныл, но тоже работает
cd ~/Dropbox
bzr branch lp:django-mode
bzr branch lp:~lol2fast4u/+junk/emacs-dir emacs
echo "(add-to-list 'load-path \"~/Dropbox/emacs\") (load-file \"~/Dropbox/emacs/config.el\")" > ~/.emacs

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

2010-02-11 21:57:45 Теги: django python apps emacs | Комментарии

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

Да очень просто.

html:
<head> ... <meta name="internal" content="mainpage" /> </head>
js: $(window).load(function (){ ... window.rel = $('meta[name=internal]').attr('content'); }); а теперь в зависимости от этой переменной делаем то, что надо. Например:
if (window.rel == 'mainpage') {
     $('#sidebar').removeClass('noJs').slideDown();
}
else if (window.rel == 'comments') {
     $('.comment').addClass('js');
}

Но самая фишка в том, что умеют шаблоны Django ;) в index.djhtml:

<head>
     ...
     <meta name="internal" content="{% block pagerel %}unknown{% endblock %}" /> {# For Javascripts, etc. #}
</head>

И в наследующих шаблонах ставим все как надо. Например, post.djhtml: {% block pagerel %}blogpost{% endblock %}

Вот и все!
Постовой: Доставка - купить недвижимость в центре москвы свежие комментарии, только на этом сайте подарки 8 марта лучшее у нас, дизель генераторы wilson оценки, справки специалистов.
2010-02-09 17:32:45 Теги: django javascript | Комментарии

С новым годом, который уже два дня как наступил. Вы все уже начитались этих поздравлений в своих Google Reader'ах и прочих читалках, да и вообще везде. Но не смотря на название, псот совсем о другом.

PyMarkup - это python-модуль для создания разметки. Делается он не столько для простоты, сколько для интеграции с приложением. шаблоны больше не нужны ;)

Идея давно уже лежала в моем Evernote (пользуясь случаем, поздравляю их с 2 миллионами пользователей!), но вот только недавно я взялся за реализацию. Пока оно умеет блоки, картинки и ссылки в виде Python'овых объектов преобразовывать в XHTML... Короче, скоро будет больше и все такое. Документация тоже будет, да.

bzr branch lp:pymarkup && cd pymarkup && sudo python setup.py install

А теперь напишем скрипт, например 1.py:

import pymarkup as p
spam = [p.e.Text('Welcome to TestSite.'),
        p.e.Image('/logo.png', 'logo', id='logo')]
spam.append(p.e.Block(id='wrapper'))
spam.append(p.e.Snippet('<p>This is a test!</p>', parent='wrapper'))
eggs = [p.e.Title('Test')]
print p.Markup(spam, eggs).render('xhtml')
И запустим:
<?xml version="1.0" ?>
<!DOCTYPE html
  PUBLIC '-//W3C//DTD XHTML 1.1//EN'
  'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>
            Test
        </title>
    </head>
    <body>
        Welcome to TestSite.
        <img alt="logo" id="logo" src="/logo.png"/>
        <div id="wrapper">
            <p>This is a test!</p>
        </div>
    </body>
</html>
Неплохо, да? А скоро будет еще больше, впрочем я это уже написал выше. UPD: теперь уже намного больше умеет. До полного XHTML чуть-чуть осталось ;)
2010-01-02 22:52:31 Теги: beta services django python apps | Комментарии

Slug - короткое название статьи.

У Django есть нужные средства. Но стоит ли нагружать сервер? Да ладно, нагрузки там почти никакой, но удобно ли? Иногда хочется исправить то, что сделано автоматически.

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

Оказалось довольно просто: в change_form.html надо заменить

{% if adminform and add %}
<script type="text/javascript">
document.getElementById("{{ adminform.first_field.auto_id }}").focus();
</script>
{% endif %}

на

{% if adminform and add %}
   <script type="application/x-javascript"
     src="http://myfreeweb.ru/media/mfwjs/jquery.1.3.2.min.js"></script>
   <script type="application/x-javascript"
    src="http://myfreeweb.ru/media/mfwjs/jquery.synctranslit.min.js"></script>
   <script type="text/javascript">
    document.getElementById("{{ adminform.first_field.auto_id }}").focus();
    $(document).ready(function () {
    if ($('#id_slug') && $('#id_name')) {
    $('#id_name').syncTranslit({destination: 'id_slug', urlSeparator: '_'});
    }
    });</script>
{% endif %}

И все хорошо :) Конечно, если поля называются не name и slug (самые очевидные названия), то надо поменять их.

2009-11-13 17:34:38 Теги: web20 django javascript | Комментарии

(для тех, кто не знает: krosswordr.ru - мой проект, словарь кроссвордных понятий)

Вот я подумал, а почему бы не добавить на krosswordr.ru немножко wiki-стиля? Не в смысле всеобщего редактирования - всего лишь ссылки между страницами. Но добавлять руками - лень, да и вообще маразм какой-то. По базе скрипт прогонять? Тоже лень, да и попортить можно.

И сделал я это прямо в шаблоне. Template Tags делаются просто. Нагрузка на сервер, скорость рендеринга? Ну так кеш же. Все работает предельно просто:

Krosswordr Autowiki

Попробовать можно, например, тут.

Постовой: расчет каско. Все страховые компании. Бесплатно.
2009-11-07 17:52:39 Теги: services web20 django | Комментарии

Недавно на Хабрахабре проскакивала новость про обновление jQTouch. Это такой плагин к известному JavaScript-фреймворку jQuery, позволяющий очень просто создавать веб-приложения для тачфонов - телефонов с сенсорным экраном, причём с пальцеориентированным интерфейсом. Каким и является iPhone. А так же HTC Hero, Dream, Magic - на Android - и куча разных WM-коммуникаторов с оболочками. Вот последнее у меня есть.

iphone_screenshot_3

Показывать буду на примере тач-версии этого блога. (Кстати, айфонщики, добавляйте. Будете читать.) Веб-приложение представляет из себя простую html-страницу, в которую нужно подключить jQuery и jQTouch, а так же тему для второго.

Я добавил в head вот это:

<script type="application/x-javascript" src="/media/jqtouch/jquery.1.3.2.min.js" charset="utf-8"></script>
<script type="application/x-javascript" src="/media/jqtouch/jqtouch.min.js" charset="utf-8"></script>
<style type="text/css" media="screen">@import "/media/themes/jqt/theme.min.css";
@import "/media/jqtouch/jqtouch.min.css";</style>

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

После подключения надо инициализировать интерфейс. Это делается функцией $.jQTouch() - и всё, больше ничего не надо писать на JS. Если, конечно, не надо AJAX'ом подгружать ничего. У меня вот так:

$.jQTouch({
    icon: 'http://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Feed-icon.svg/128px-Feed-icon.svg.png',
    statusBar: 'black-translucent',
    preloadImages: [
        '/media/themes/jqt/img/chevron_white.png',
 *пути_к_всяким_картинкам*
        ]
});

Разумеется, здесь надо подправить загружаемую графику на ту, что ты чаще используешь. Для скорости. И иконку, она будет иконкой приложения в меню iPhone.

Теперь можно просто использовать обычные XHTML-теги. Но сначала расскажу о самом главном. Страницы - главное в приложении. Страница представляет из себя простой блок (div) c (понятным) id. Первый див будет первой страницей, которая будет открываться при нажатии на иконку в телефоне. Чтобы переходить между страницами, на первой должна быть ссылка на вторую, то есть a href="#id_страницы".

Для создания верхнего бара делаем вложенный в страницу div class="toolbar". Заголовок в нём - просто обычный h1. Кнопка "назад" - a class="back button" href="#id_задней_страницы". Вообще, чтобы узнать больше о элементах интерфейса, смотрите исходный код демки.

А теперь самое главное - интеграция с Django. Мы же делаем тач-версию блога, так? Я не знаю, как у тебя устроены модели и виды, но у меня список постов - content.object_list. Просто делаем шаблон, в котором в head вся инициализация, описанная выше, а в body... Особая Django'вская магия ;) Начнём с главной страницы. Это - список постов блога. По нажатию на один из них - страница с самим постом. Логично, да?

<div id="main">
  <div class="toolbar"><h1>MyFreeWeb Touch</h1></div>
  <div id="content">
    <ul>
      {% for post in content.object_list %}
      <li class="arrow"><a href="#{{ post.slug }}">{{ post.name }}</a></li>
       {% endfor %}
    </ul>
  </div>
</div>

Мало кода, да? Просто заголовок и список постов. А теперь делаем настоящую магию. Для каждого поста создаём свою страницу с id равным его slug (короткое имя на латинице, с _ вместо пробелов, и без лишних символов. Переводить как это слово - не знаю.) - мы ссылались на эти страницы в главной.

{% for post in content.object_list %}
<div id="{{ post.slug }}">
  <div class="toolbar">
    <a class="back button" href="#main">Назад</a>
      <h1>MFW:{{ post.name }}</h1>
  </div>
  <div class="post">{{ post.text|safe|urlize }}</div>
  <div class="info">Написан {{ post.date }}{% if post.tags %} | 
Теги (открываются в обычной версии):{% for tag in post.tags.filter %}
<a href="/tag/{{tag.name}}">{{ tag.name }}</a> {% endfor %}{% endif %}</div>
</div>
{% endfor %}

Да вот и всё. Вот так Это выглядит на моём AnyDATA ASP-505A:

asp_screenshot_1asp_screenshot_2

А вот как на iPhone, спасибо @_corwin_ (follow! follow!!!):

iphone_screenshot_0iphone_screenshot_1iphone_screenshot_2

Короче, теперь веб-приложения для iPhone и коммуникаторов вообще делать очень просто. Вот такие дела.

Постовой:
Дома лучше, а то вдруг пробки. вызов ветеринара на дом
Прорезные карманы
2009-09-01 17:40:49 Теги: web20 django blog apps javascript markup | Комментарии
Вот я и переехал на свой движок, написанный на Django. Заодно и сменил дизайн. Да, из старых постов взял только лучшие. URL'ы поменялись...
2009-06-15 00:16:25 Теги: django python blog | Комментарии
Снимок-Блог Василия Пупкина - Shiretoko
Допустим, вы хотите написать веб-приложение. Пусть это будет движок для блога. На PHP надо написать, как приложение будет сохранять в базу данных переданные ему данные (в админке) и отображать их для пользователя. А так же закрыть уязвимости. Представьте, если не нужно писать код для обращения с базой данных. И не надо самому изобретать функции обработки шаблонов. А так же уязвимости не возникают. Это не мечта, это Django. Фреймворк для создания веб-приложений на простом, но мощном языке Python. Попробуем? Для начала установим Python версии выше 2.3. Потом скачаем Django с официального сайта. Не ставьте из убунтовских репозиториев, а то придётся делать лишние движения типа изменений PATH и добавления прав запуска для скриптов. Скачали, распаковали,
sudo python setup.py install
сделали. Готово! Можно приступать. Создаём проект и приложение. (Проект может содержать несколько приложений, а приложение можно копировать в разные проекты. Понятно?) Мы делаем личный блог. Назовём проект vasyasite, а приложение blog.
django-admin.py startproject vasyasite cd vasyasite django-admin.py startapp blog
Отлично. Мы готовы, можно протестировать встроенный сервер... Так, я сказал "встроенный сервер"? Да, Django предоставляет разработчикам сервер для тестирования, написанный на Python. (Где вы ещё видели такую заботу о разработчиках?) python manage.py runserver Теперь по адресу http://127.0.0.1:8000/ находится проект vasyasite. Там сейчас только страница с сообщением о том, что Django отлично работает. Ctrl+C его, да! Пока нам сервер не понадобится. Создадим в папке проекта папки templates и media. Надо бы настроить проект, для этого редактируем settings.py. Мы будем использовать SQLite для баз данных - это просто. Прописываем 'sqlite3' в DATABASE_ENGINE и путь к файлу в DATABASE_NAME. У меня '/home/lol2fast4u/vasyasite/blog.db'. Если такого файла нет - он автоматически создаётся. Не забывайте сменить TIME_ZONE на свою (у меня Europe/Moscow) и LANGUAGE_CODE на 'ru-ru'. Сами догадаетесь, куда прописать созданные папки media и templates, конфиг интуитивно понятен. Тем, кто знает английский %) В INSTALLED_APPS надо дописать плагин комментариев(да. он здесь встроенный есть!), админпанель и своё приложение. У меня выглядит так:
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'django.contrib.comments',
    'vasyasite.blog',
)
Теперь надо создать модели данных. Они представляют из себя простые питоновские классы. Мы пишем простой блог, значит у нас есть категории и посты. У категории есть название, у поста - категория, дата/время, название и содержание. Вот что надо поместить в blog/models.py:
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)
    def __unicode__(self):
        return self.name
class Post(models.Model):
    category = models.ForeignKey(Category)
    name = models.CharField(max_length=100)
    datetime = models.DateTimeField('Date published')
    content = models.TextField(max_length=100000)
    def __unicode__(self):
        return self.name
Обратите внимание на функцию __unicode__: она возвращает название объекта в список. Чтобы список можно было человеку почитать, если он зайдёт в интерактивную консоль ( python manage.py shell ). А теперь (в папке с проэктом) надо запустить python manage.py syncdb - эта команда создаст все нужные базы данных. Поскольку у нас в приложениях прописана авторизация, скрипт попросит придумать логин, е-мейл и пароль администратора. Теперь настроим админку. В папке приложения (blog) создаём файл admin.py. В него прописываем, с какими объектами можно будет управлять из админки. Вот что у меня:
from vasyasite.blog.models import Category, Post
from django.contrib import admin

admin.site.register([Category, Post])
Осталось написать публичный вид, "морду" блога. Будем использовать шаблоны. Сначала создаём "виды". Их будет три: главная(все посты), категория(посты одной категории) и один пост. Редактируем views.py (который в папке приложения). У меня получился такой:
from django.shortcuts import render_to_response
from vasyasite.blog.models import Category, Post

def main(request):
    posts = Post.objects.order_by('-id')
    categories = Category.objects.order_by('-id')
    return render_to_response('index.html', {'posts': posts, 'categories': categories, 'iscomments': 'false'})
def category(request, category_id):
    posts = Post.objects.filter(category=category_id).order_by('-id')
    categories = Category.objects.order_by('-id')
    return render_to_response('index.html', {'posts': posts, 'categories': categories, 'iscomments': 'false'})
def post(request, post_id):
    posts = Post.objects.filter(id=post_id)
    categories = Category.objects.order_by('-id')
    return render_to_response('index.html', {'posts': posts, 'categories': categories, 'iscomments': 'true'})
Так, подождите. Один шаблон для всех видов? Да, это так. Всё прописывается в шаблоне. Я сделал его в своём же генераторе и положил в templates. Теперь надо отредактировать, чтобы было примерно так:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
    <head>
        <title>Блог Василия Пупкина</title>
        <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
        <style type="text/css">
        
body {
    margin: 0;
    padding: 0;
}

#header {
    background: #edd400;
    margin-bottom: 1em;
}
h1 {    font: 2em sans-serif; }
h2 {    font: 1.2em sans-serif; }

#sidebar {
    background: #c4a000;
    float: left;
    width: 10em;
    display: inline;    
    margin-left: 1em;
}

#content {
    margin-left: 12em;
    margin-right: 1em;
}
.post {
    background: #c4a000;
    padding: 1em;
    margin: 1em 0em 1em 0em;
}
.meta {
   border: 0.2em dotted #edd400;
   margin: 0.1em;
}
#footer {
    background: #edd400;
    clear: both;
}
        </style>
    </head>
    <body>
        <div id="header">
            <h1><a href="/">Блог Василия Пупкина</a></h1>
            <h2>Работает на Django</h2>
        </div>
        <div id="sidebar">
            Категории:
            <ul>
                {% for category in categories %}
                    <li><a href="/category/{{ category.id }}">{{ category.name }}</a></li>
                {% endfor %}
            </ul>
        </div>
        <div id="content">
            {% for post in posts %}
                <div class="post">
                    <div class="meta">{{ post.datetime }} <a href="/category/{{ post.category.id 
}}">{{ post.category.name }}</a><a href="/post/{{ post.id }}">{{ post.name }}</a></div>
                    {{ post.content }}
                    
                    {% ifequal iscomments 'true' %}
                        {% load comments %}
                        {% get_comment_list for post as allcomments %}
                        {% for acomment in allcomments %}
                            <div class="meta"><a href="{{ acomment.user_url }}">{{ acomment.user_name }}
</a>: {{ acomment.comment }}</div>
                        {% endfor %}
                        <div class="meta">{% render_comment_form for post %}</div>
                    {% endifequal %}
                </div>
            {% endfor %}
        </div>
        <div id="footer">
            <p>Разметка от <a href="http://myfreeweb.ru">MyFreeWeb.ru</a></p>
        </div>
    </body>
</html>
Заметили, что в шаблоне мы указали URL'ы, которых мы нигде больше не указывали? Самое время их указать. Открываем urls.py (в директории проэкта). Раскомментируем строчки для админпанели и добавляем свои для видов. А ещё для комментариев одну. Получается что-то такое:
urlpatterns = patterns('vasyasite.blog.views', 
    (r'^$', 'main'), 
    (r'^category/(?P<category_id>\d+)/$', 'category'), 
    (r'^post/(?P<post_id>\d+)/$', 'post'), 
    (r'^admin/(.*)', admin.site.root), 
    (r'^comments/', include('django.contrib.comments.urls')), 
)
Активируем сервер, заходим на http://127.0.0.1:8000/ и получаем ошибку - скрипт не может взять посты т.к. мы их не писали! Заходим в админку http://127.0.0.1:8000/admin, логинимся (помните, указывали логин и пароль, когда syncdb спрашивал?). Интерфейс понятный :) Создаём категорию и пост. Заходим обратно на http://127.0.0.1:8000/ и видим... Ура!!! Движок работает. Можно рассказывать друзьям, "какой я крутой" и вести блог. Снимок-Блог Василия Пупкина - Shiretoko-1 Домашнее задание: прикрутить RSS и комментарии IntenseDebate. P.S. Читайте официальную документацию!
Постовой: Здесь можно купить охотничье ружьё Лучшие обои для мобильного
Фентези обои для мобильного телефона
Как скачать фильмы из интернета?
Мануальный массаж на дому в пределах МКАД.
2009-05-24 16:30:18 Теги: django python blog | Комментарии