Python Pyramid - 包结构

Cookiecutter 实用程序会自动在同名的父项目文件夹中创建一个包文件夹。 包文件夹由以下文件和子文件夹组成。


__init__.py

一个文件夹需要 __init__.py 文件才能被视为一个 Python 包。 testproj 包也有这个文件,它本质上声明了 development.ini 的 Pyramid WSGI 应用程序项目,以将其用作入口点。

应用程序对象由 main() 函数返回。 它通过包含在运行 cookiecutter 时选择的模板库来配置应用程序注册表,包括 routes 模块并通过扫描现有包将视图添加到配置器。 以下 Python 代码自动生成为 __init__.py 文件。

from pyramid.config import Configurator
def main(global_config, **settings):
   """ This function returns a Pyramid WSGI application.
   """
   with Configurator(settings=settings) as config:
      config.include('pyramid_jinja2')
      config.include('.routes')
      config.include('.models')
      config.scan()
   return config.make_wsgi_app()

routes.py

Cookiecutter 实用程序会自动生成一个 Python 脚本,该脚本具有一个名为 includeme() 的函数。 它添加了一个静态路由和一个指向"/"URL 模式的主路由。

def includeme(config):
   config.add_static_view('static', 'static', cache_max_age=3600)
   config.add_route('home', '/')

这些路由通过上述 __init__.py 文件中的 main() 函数添加到应用程序配置中。


Views 视图包

项目包(在我们的例子中是 testproj 包)包含这个视图子包 - 一个包含空白 __init__.py 的文件夹,一个名为 default.py 的 Python 模块,其中包含定义一个名为 my_view() 的视图函数。 它将项目名称作为上下文发送到预构建模板 mytemplate.jinja2

from pyramid.view import view_config
from pyramid.response import Response
from sqlalchemy.exc import SQLAlchemyError
from .. import models

@view_config(route_name='home', renderer='testproj:templates/mytemplate.jinja2')
def my_view(request):
   try:
      query = request.dbsession.query(models.MyModel)
      one = query.filter(models.MyModel.name == 'one').one()
   except SQLAlchemyError:
      return Response(db_err_msg, content_type='text/plain', status=500)
   return {'one': one, 'project': 'testproj'}
   
db_err_msg = """\
Pyramid is having a problem using your SQL database.
....
"""

default.py 脚本还在模型子包中导入了 mymodel 的定义。 这个视图包还在 notfound.py 文件中定义了一个 notfound 视图。

from pyramid.view import notfound_view_config
@notfound_view_config(renderer='testproj:templates/404.jinja2')
def notfound_view(request):
   request.response.status = 404
   return {}

Static 静态文件夹

testproj 包文件夹下的这个文件夹包含 Pyramid 徽标文件和主页的 theme.CSS。


Templates 模板文件夹

我们知道网页模板需要存放在templates文件夹中。 此子文件夹包含 jinja2 模板。 这里我们有一个名为 layout.jinja2 的基本模板,它由 mytemplate.jinja2 继承,由 my_view() 视图函数呈现。

{% extends "layout.jinja2" %}

{% block content %}
<div class="content">
   <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
   <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, a Pyramid application generated by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
{% endblock content %}

Models 模型包

tesptproj 包文件夹下的这个子包包含 mymodel.py,它具有名为 MyModel 的 SQLAlchemy 模型定义。

from sqlalchemy import (
   Column,
   Index,
   Integer,
   Text,
)

from .meta import Base
class MyModel(Base):
   __tablename__ = 'models'
   id = Column(Integer, primary_key=True)
   name = Column(Text)
   value = Column(Integer)
Index('my_index', MyModel.name, unique=True, mysql_length=255)

meta.py 在 SQLAlchemy 中声明了一个 Declarative Base class 的对象。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import MetaData

NAMING_CONVENTION = {
   "ix": "ix_%(column_0_label)s",
   "uq": "uq_%(table_name)s_%(column_0_name)s",
   "ck": "ck_%(table_name)s_%(constraint_name)s",
   "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
   "pk": "pk_%(table_name)s"
}
metadata = MetaData(naming_convention=NAMING_CONVENTION)
Base = declarative_base(metadata=metadata)