Есть ли лучший способ переключения между выходом 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')
Я подозреваю, что приближаюсь к этому неправильно...?
Ответы
Ответ 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 для ответа.