Websauna项目教程:创建你的第一个视图(View)
视图(Views)基础概念
在Websauna框架中,视图(View)是处理特定URL请求的Python函数或类。每个视图通常对应应用程序中的一个特定功能页面,并负责处理业务逻辑和渲染模板。视图是Web应用程序的核心组成部分,它们决定了用户在不同URL下看到的内容和交互方式。
视图的典型应用场景
以一个博客系统为例,常见的视图可能包括:
- 博客首页:显示最新发布的文章
- 文章详情页:展示单篇文章的完整内容
- 按年归档页:显示某年所有有文章的月份
- 按月归档页:显示某月所有有文章的日期
- 按日归档页:显示某日所有文章
- 评论功能:处理对文章的评论提交
URL路由机制
Websauna使用Pyramid框架的路由器(Router)系统来处理URL到视图的映射,这个过程称为URL分发(URL dispatch)。这是构建Web应用最常用的方式。
两种路由方式对比
-
URL分发(URL dispatch):
- 通过定义URL模式直接映射到视图
- 适合大多数常规Web应用场景
- 示例URL模式:
/newsarchive/<year>/<month>/
-
遍历(Traversal):
- URL路径各部分映射到Python对象(资源)
- 适合有层次结构的复杂应用
- 提供更灵活的访问控制机制
创建实际视图
视图通常有以下几种行为模式:
- 返回包含页面内容的Response对象
- 返回HTTP错误代码实例
- 抛出异常(此时数据库事务会自动回滚)
- 返回供渲染器使用的对象(通常是传递给模板的字典)
基础视图示例
以下是一个简单的视图示例,它从数据库查询最新的5个问题并显示:
from pyramid.request import Response
from .models import Question
def home(request: Request):
"""渲染网站首页"""
latest_question_list = request.dbsession.query(Question).order_by(Question.published_at.desc()).all()[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return Response(output)
使用模板系统
直接在视图中硬编码HTML不是好的实践。Websauna默认使用Jinja2模板引擎,可以很好地分离业务逻辑和表现层。
模板结构组织
建议采用命名空间方式组织模板文件:
- 将模板放在
myapp/templates/myapp/
目录下 - 这样可以避免不同应用间的模板命名冲突
模板继承机制
Websauna提供了基础模板site/base.html
,包含Bootstrap框架的基本布局(导航栏、页脚等)。自定义模板可以继承它:
{% extends "site/base.html" %}
{% block content %}
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>
<a href="{{ 'detail'|route_url(question_uuid=question.uuid|uuid_to_slug) }}">
{{ question.question_text }}
</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>暂无可用投票。</p>
{% endif %}
{% endblock %}
视图与模板结合
更新后的视图使用模板渲染:
from .models import Question
@simple_route("/", route_name="home", renderer="myapp/home.html")
def home(request: Request):
"""渲染网站首页"""
latest_question_list = request.dbsession.query(Question).order_by(Question.published_at.desc()).all()[:5]
return locals()
高级主题
UUID与Slug转换
Websauna推荐使用UUID而非数据库ID作为公开标识符,这提高了安全性。框架提供了方便的转换工具:
uuid_to_slug
: 将UUID转换为base64编码的字符串slug_to_uuid
: 将slug字符串转换回UUID对象
404错误处理
当请求的资源不存在时,视图可以抛出HTTPNotFound异常:
from pyramid.httpexceptions import HTTPNotFound
@simple_route("/questions/{question_uuid}", route_name="detail", renderer="myapp/detail.html")
def detail(request):
question_uuid = slug_to_uuid(request.matchdict["question_uuid"])
question = request.dbsession.query(Question).filter_by(uuid=question_uuid).one_or_none()
if not question:
raise HTTPNotFound()
return locals()
模板变量与过滤器
Jinja模板支持丰富的变量操作和过滤器:
<!-- 使用点表示法访问对象属性 -->
<h1>{{ question.question_text }}</h1>
<!-- 使用for循环遍历集合 -->
<ul>
{% for choice in question.choices %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
Websauna提供了许多内置模板过滤器,如uuid_to_slug
等,可以简化模板开发。
通过本教程,你应该已经掌握了在Websauna中创建基本视图的核心概念和方法。记住良好的实践包括:使用模板分离逻辑与表现、采用UUID而非数据库ID、合理组织模板文件结构等。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考