About Blog Dev | Alfa Romeo SZ Conkeror wishlist

render_to improved

[UPD от 12 ночи]

Чуть больше года назад, когда меня окончательно задолбало писать render_to_response c кучей параметров, я себе написал маленький декоратор render_to, который заметно уменьшал количество писанины.

Но вот не так давно обсуждали его в джаббер-конференции pythonua@c.j.r (кстати, официальная конференция python.com.ua), где появилась идея слегка его проапгрейдить до возможности задавать темплейт из view (когда одна вью может выдавать различные странички). В принципе, идея усложнения декоратора мне не особенно нравится (да и потом, кому надо — может переделать себе, благо несложно), но по размышлении я увидел, что особенного усложнения нету, плюс сохраняется обратная совместимость полностью (что важно, потому как мне есть и где использовать новую фичу, но не очень хочется ломать все вьюхи, использующие старую версию ;).

Однако первая версия, с дополнительным параметром (именем ключа из возвращаемого словаря), имеет явно менее питоновский привкус, чем вариант, предложенный в комментариях. Теперь можно возвращать дополнительно к словарю ещё и имя темплейта, в который он должен отрисовываться:

@render_to('some/thing_detail.html')
def thing_detail(request):
    ...
    return {'obj': obj}, 'other/thing.html'

Есть один небольшой момент: если возвращается тупль, то первый аргумент не проверяется на свою словарность — для определения типа это не нужно, а программист пускай по своим граблям шагает смело. ;)

def render_to(template):
    """
    Decorator for Django views that sends returned dict to render_to_response function
    with given template and RequestContext as context instance.

    If view doesn't return dict then decorator simply returns output.
    Additionally view can return two-tuple, which must contain dict as first
    element and string with template name as second. This string will
    override template name, given as parameter

    Parameters:

     — template: template name to use
    """
    def renderer(func):
        def wrapper(request, *args, **kw):
            output = func(request, *args, **kw)
            if isinstance(output, (list, tuple)):
                return render_to_response(output[1], output[0], RequestContext(request))
            elif isinstance(output, dict):
                return render_to_response(template, output, RequestContext(request))
            return output
        return wrapper
    return renderer

P.S.Явно в этот раз я из всей работы только то и сделал, что в блог написал… Ну да это мелочи, главное — удобно получилось. :-)

Add post to: Delicious Reddit Slashdot Digg Technorati Google
Comment

Pingbacks

Kosti zebry» Blog Archive » Ještě vylepšenější render_to @kosti.zebry.cz 24.06.2008 17:24
Alexandr Solovyov vytvořil pěkný dekorátor pro Django. Jde o to, že view namísto render_to_response vrací pouze slovník, a dekorátorem render_to se zařídí vše ostatní. Jméno šablony se definuje ve formě parametru, nebo zevnitř view:

Comments

Хрюндель 22.03.2008 18:14

Нет, ну вот скажите люди, разве не должен ли быть default_template изначально None?

reply
Большой Лис 22.03.2008 18:57

нет, не должен, ибо тогда ему нечего будет рендерить?

reply
Хрюндель 22.03.2008 19:37

дык если ты ему не задашь никаких параметров ему так и так нечего будет рендрить

reply
Jungle 22.03.2008 20:06

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

def response(template_path=None):
    def decor(func):
        def wrapper(request, *args, **kwargs):
            data = func(request,*args, **kwargs)
            if template_path and isinstance(data, dict):
                return render_to_response(template_path, data, RequestContext(request))
            elif isinstance(data, basestring):
                return HttpResponse(data)
            else:
                return data
        return wrapper
    return decor

т.е. если нет шаблона и даные являются строкой, то возврашаем HttpResponse(data)

reply
Александр Соловьёв 22.03.2008 23:41

Хе-хе, он несколько другой вариант развития имел в виду. :-)

reply
Jungle 23.03.2008 7:14

теперь понял :) ступил однако

reply
Александр Соловьёв 22.03.2008 23:39

Не должен быть. А в текущем варианте ещё и не может. :-)

reply
Jungle 22.03.2008 19:12

а у меня почти аналогично как у тебя :)

from django.http import HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.conf import settings

def response(template_path):
    def decor(func):
        def wrapper(request, *args, **kwargs):
            data = func(request,*args, **kwargs)
            if isinstance(data, dict):
                return render_to_response(template_path, data, RequestContext(request))
            else:
                return data
        return wrapper
    return decor

def response_jsonp(to_json, callback, content_type='text/javascript; charset=%s;' % settings.DEFAULT_CHARSET):
    import simplejson
    content = u'%s(%s)\n' % (callback, simplejson.dumps(to_json))
    return HttpResponse(content, content_type)

только ещё добавил response_jsonp полезная штука.

reply
Александр Соловьёв 22.03.2008 22:34

Ну, для JSON’а у меня тоже есть отдельный, в исходниках byteflow можно увидеть. :-)

reply
kleptos 22.03.2008 19:41

вай нот return {‘bar’: bar}, template_name

ну и соотв: elif isinstance(data, (list, tuple)): # у нас есть имя шаблона

reply
Александр Соловьёв 22.03.2008 22:36

Хмм… Скорее по недосмотру. Мне нравится идея. :-)

reply
kleptos 23.03.2008 17:07

Незнаю, на мой взгляд это саоочевидное решение. Тем более на фоне совсем грязного хака template_key_name.

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

reply
Александр Соловьёв 23.03.2008 17:58

Очевидное оно только тогда, когда отвлечёшься от словаря.

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

Да ну, всё несколько веселее на самом деле.

reply
kleptos 23.03.2008 21:49

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

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

reply
Александр Соловьёв 24.03.2008 12:02

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

Хм. А можно пальцем на это указать, плз?

reply
kleptos 27.03.2008 2:24

Да любой view. У меня даже скрейперы вразумительнее выглядят.

reply
Александр Соловьёв 27.03.2008 9:23

Хз, наверное я уже просто привык. :-)

reply
kleptos 27.03.2008 23:47

Да, после сегодняшних копаний в потрохах sqlalchemy, склонен согласиться. Можно привыкнуть практически к чему егодно.

reply
kleptos 27.03.2008 2:24

алсо, можно было-бы прикрутить какую-нить нотификацию “вам ответили”

reply
Александр Соловьёв 27.03.2008 9:22

Нужно было бы… Пока ещё нету. :(

reply
Yuri Baburov 26.03.2008 23:44

ну я вместо

{'obj': obj}, 'other/thing.html'

в своем аналоге под названием @page пользую

{'obj': obj, 'template': 'other/thing.html'}

ну скажите мне, кто будет использовать переменную template для чего-нибудь, кроме имени шаблона? :)

reply
Александр Соловьёв 27.03.2008 1:21

Это было первым вариантом реализации, но оно не такое прикольное, имхо. :-)

reply

Comment form for «render_to improved»

Required. 30 chars of fewer.

Required.