10:处理Web请求和响应

Web应用程序处理传入请求并返回传出响应。Pyramid使处理请求和响应变得方便和可靠。

目标

  • 了解Pyramid对请求和响应的选择的背景。

  • 从请求中获取数据。

  • 更改响应头中的信息。

背景

为Web开发意味着处理Web请求。由于这是Web应用程序的关键部分,因此Web开发人员需要一套健壮、成熟的软件来处理Web请求并返回Web响应。

Pyramid一直很好地适应了现有的python web开发世界(虚拟环境、打包、cookiecutters、首先使用python 3等等)。Pyramid变成了著名的 WebOb 用于请求和响应处理的python库。在上面的例子中,Pyramid手 hello_worldrequest 那就是 based on WebOb .

步骤

  1. 首先我们复制 view_classes 步骤:

    cd ..; cp -r view_classes request_response; cd request_response
    $VENV/bin/pip install -e .
    
  2. 简化 request_response/tutorial/__init__.py

    1from pyramid.config import Configurator
    2
    3
    4def main(global_config, **settings):
    5    config = Configurator(settings=settings)
    6    config.add_route('home', '/')
    7    config.add_route('plain', '/plain')
    8    config.scan('.views')
    9    return config.make_wsgi_app()
    
  3. 我们只需要一个视野 request_response/tutorial/views.py

     1from pyramid.httpexceptions import HTTPFound
     2from pyramid.response import Response
     3from pyramid.view import view_config
     4
     5
     6class TutorialViews:
     7    def __init__(self, request):
     8        self.request = request
     9
    10    @view_config(route_name='home')
    11    def home(self):
    12        return HTTPFound(location='/plain')
    13
    14    @view_config(route_name='plain')
    15    def plain(self):
    16        name = self.request.params.get('name', 'No Name Provided')
    17
    18        body = 'URL %s with name: %s' % (self.request.url, name)
    19        return Response(
    20            content_type='text/plain',
    21            body=body
    22        )
    
  4. Update the tests in request_response/tutorial/tests.py

     1import unittest
     2
     3from pyramid import testing
     4
     5
     6class TutorialViewTests(unittest.TestCase):
     7    def setUp(self):
     8        self.config = testing.setUp()
     9
    10    def tearDown(self):
    11        testing.tearDown()
    12
    13    def test_home(self):
    14        from .views import TutorialViews
    15
    16        request = testing.DummyRequest()
    17        inst = TutorialViews(request)
    18        response = inst.home()
    19        self.assertEqual(response.status, '302 Found')
    20
    21    def test_plain_without_name(self):
    22        from .views import TutorialViews
    23
    24        request = testing.DummyRequest()
    25        inst = TutorialViews(request)
    26        response = inst.plain()
    27        self.assertIn(b'No Name Provided', response.body)
    28
    29    def test_plain_with_name(self):
    30        from .views import TutorialViews
    31
    32        request = testing.DummyRequest()
    33        request.GET['name'] = 'Jane Doe'
    34        inst = TutorialViews(request)
    35        response = inst.plain()
    36        self.assertIn(b'Jane Doe', response.body)
    37
    38
    39class TutorialFunctionalTests(unittest.TestCase):
    40    def setUp(self):
    41        from tutorial import main
    42
    43        app = main({})
    44        from webtest import TestApp
    45
    46        self.testapp = TestApp(app)
    47
    48    def test_plain_without_name(self):
    49        res = self.testapp.get('/plain', status=200)
    50        self.assertIn(b'No Name Provided', res.body)
    51
    52    def test_plain_with_name(self):
    53        res = self.testapp.get('/plain?name=Jane%20Doe', status=200)
    54        self.assertIn(b'Jane Doe', res.body)
    
  5. 现在运行测试:

    $VENV/bin/pytest tutorial/tests.py -q
    .....
    5 passed in 0.30 seconds
    
  6. 运行 Pyramid 应用程序时使用:

    $VENV/bin/pserve development.ini --reload
    
  7. 在浏览器中打开http://localhost:6543/。您将被重定向到http://localhost:6543/plain。

  8. 打开http://localhost:6543/plain?name=Alice在您的浏览器中。

分析

在这个视图类中,我们有两个路由和两个视图,第一个通过HTTP重定向指向第二个。Pyramid形罐头 generate redirects 从视图中返回特殊对象或引发特殊异常。

在这个Pyramid视图中,我们从 request.url . 另外,如果您访问了http://localhost:6543/plain?name=alice,名称包含在响应正文中:

URL http://localhost:6543/plain?name=alice with name: alice

最后,我们设置响应的内容类型和主体,然后返回响应。

我们更新了单元测试和功能测试,以证明我们的代码执行重定向,但也处理发送和不发送 /plain?name .

额外credit

  1. 我们也可以 raise HTTPFound(location='/plain') 而不是退回?如果是,有什么区别?