Подтвердить что ты не робот

Есть ли лучший способ переключения между выходом HTML и JSON в Pyramid?

# /test{.format} no longer seems to work...
config.add_route('test', '/test.{ext}', view='ms.views.test')

views.py:

from pyramid.response import Response
from pyramid.renderers import render

import json

def test(request):
    extension = request.matchdict['ext']
    variables = {'name' : 'blah', 'asd' : 'sdf'}

    if extension == 'html':
        output = render('mypackage:templates/blah.pt', variables, request=request)

    if extension == 'json':
        output = json.dumps(variables)

    return Response(output)

Есть ли более простой способ сделать это? С Pylons это было просто:

def test(self, format='html'):
    c.variables = {'a' : '1', 'b' : '2'}

    if format == 'json':
        return json.dumps(c.variables)

    return render('/templates/blah.html')

Я подозреваю, что приближаюсь к этому неправильно...?

4b9b3361

Ответ 1

Я думаю, лучший способ - добавить один и тот же взгляд дважды с разностными рендерерами. Предположим, что мы имеем следующее представление:

def my_view(request):
    return {"message": "Hello, world!"}

Теперь в нашей конфигурации мы можем добавить один и тот же вид дважды:

from pyramid.config import Configurator
config = Configurator()
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako")
config.add_route('test', '/test', my_view, renderer="json", xhr=True)

Что мы имеем сейчас:

  • Просмотреть my_view будет отображать шаблон "templates/my_template.mako" с возвращенным dict, предоставленным в качестве контекста, если мы укажем наш браузер на URL /test.
  • Если мы сделаем запрос XHR с my_view, вызывается снова, но теперь возвращаемый dict будет закодирован как JSON и передан обратно вызывающему абоненту (пожалуйста read docs о проверке выполнения запроса с помощью XHR).

Та же самая идея, которую мы можем использовать для определения разных маршрутов, но с одним и тем же представлением:

from pyramid.config import Configurator
config = Configurator()
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako")
config.add_route('test_json', '/test.json', my_view, renderer="json")

Теперь /test запускает рендеринг шаблона, но /test.json возвращает только закодированную строку JSON.

Вы можете пойти дальше и отправить диспетчеру в правый рендеринг с помощью аргумента accept метода add_router:

from pyramid.config import Configurator
config = Configurator()
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako")
config.add_route('test', '/test', my_view, renderer="json", accept="application/json")

Если запрос поставляется с заголовком accept, установленным в application/json, будет возвращено значение JSON, иначе вы получите отображаемый шаблон.

Примечание. Это будет работать только в том случае, если у вас есть предопределенный набор форматов данных, в которых вы хотите кодировать ответы из своих представлений, но это обычный случай. Если вам нужна динамическая диспетчеризация, вы можете украсить свои представления аргументом decorate add_route, который выберет правильный рендерер с вашими правилами.

Ответ 2

Это то, что вы ищете? Пилоны и пирамида имеют разные API. Поэтому они будут разными. Вы можете сделать их немного более похожими, но вы не можете сделать их идентичными.

def test(request):
    extension = request.matchdict['ext']
    variables = {'name' : 'blah', 'asd' : 'sdf'}

    if extension == 'json':
        return Response( json.dumps(variables) )

    return Response( render('mypackage:templates/blah.pt', variables, request=request) )

Ответ 3

Pyramid Отправка URL-адреса очень мощная и гибкий механизм. Прежде всего, мы напишем правильный шаблон url. В синтаксисе шаблона маршрута мы можем использовать регулярные выражения для замещающих маркеров,

'/test{ext:\\..*}'

Здесь мы видим, что путь URL должен содержать. (период), а затем любые символы. Все символы в том числе. (период) будет находиться под ключом ext в request.matchdict.

Конечно, мы можем усложнить регулярное выражение, чтобы указать, какие расширения могут быть:

'/test{ext:\\.(html|json)}'

Затем мы добавляем маршрут с нашим шаблоном:

config.add_route('test',
                 pattern='/test{ext:\\.(html|json)}')

Хотите добавить, что мы можем указать набор расширений с помощью пользовательских предикатов.

Чтобы указать расширение по умолчанию, мы можем использовать простой pregenerator.

def default_extension(ext):
    def pregenerator(request, elements, kw):
        if 'ext' not in kw:
            kw['ext'] = ext

        return elements, kw

    return pregenerator

config.add_route('test',
                 pattern='/test{ext:\\.(html|json)}',
                 pregenerator=default_extension('.html'))

request.route_path('test')
# '/test.html'
request.route_path('test', ext='.json')
# '/test.json'

После этого мы Traversal, чтобы помочь нам переключаться между html и json выход:

config.add_route('test',
                 '/test{ext:\\.(html|json)}',
                 pregenerator=default_extension('.html'),
                 traverse='{ext}')

С аргументом traverse в add_route мы вынуждаем наше приложение hybrid. И мы должны понимать, что factory, который предоставит контекст для наших представлений, не должен содержать ключей, соответствующих нашим расширениям. По умолчанию root factory не работает.

views.py:

from pyramid.view import view_config, view_defaults


@view_defaults(route_name='test')
class Test(object):
    def __init__(self, request):
        self.request = request
        self.variables = {
            'name': 'blah',
            'asd': 'sdf'
        }

    @view_config(name='.html', renderer='mypackage:templates/blah.pt')
    def html(request):
        return {
            'request': request,
            'variables': self.variables
        }

    @view_config(name='.json', renderer='json')
    def json(request):
        return {
            'request': request,
            'variables': self.variables
        }

Здесь мы создали class Test и укажите для него имя маршрута. Затем мы разделили методы по именам наших расширений.

Ответ 4

Попробуйте следующим образом:

def test(self, format='html'):
    c.variables = {'a' : '1', 'b' : '2'}

    if format == 'json':
        return Response(json = c.variables)

    return render_to_response('/templates/blah.html')

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