pyramid基本用法


模板

alchemy:基礎功能加數據庫--常用

starter:只包含pyramid最基本功能,簡單模板,無數據庫

zodb:

創建項目

pcreate -s alchemy 項目名稱

 項目創建完成后進入到項目路徑

python setup.py develop  # 不會把代碼復制過去,會在site-packages里創建一個路徑,還是回去項目目錄里找代碼

python setup.py install  # 把項目需要的依賴全部復制到site-packages里,就算是把項目目錄刪掉都可以用,會導致項目里改代碼的話不生效

查看MyProject.egg-link

/home/python/.virtualenv/虛擬環境/lib/python2.7/site-packages

這里有MyProject.egg-link和其它的一些依賴

依賴包

 打開debug調試

在development.ini中打開

debugtoolbar.hosts = 192.168.2.3  # 輸入想在哪個ip調試

 development.ini詳細介紹

###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###

[app:main]  # 一個中括號是一個節
use = egg:MyProject  # egg后面跟項目名稱

pyramid.reload_templates = true  # 對模板進行修改后是否自動重載,開發階段可以用來調試,正式環境會降低渲染速度 
pyramid.debug_authorization = false  # 認證和權限相關的調試信息
pyramid.debug_notfound = false  # 找不到頁面的時候提示相關信息
pyramid.debug_routematch = false  # url映射機制調試
pyramid.default_locale_name = en  # 程序默認語言
pyramid.includes =        # 可以多條 加載pyramid相關插件
    pyramid_debugtoolbar
    pyramid_tm

sqlalchemy.url = sqlite:///%(here)s/devdata.db
# sqlalchemy.url = mysql://root:mysql@localhost:3306/pyramid_myproject?charset=utf8
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1  # 調試工具條 只能在本地使用

###
# wsgi server configuration
###

[server:main]
use = egg:waitress#main
host = 192.168.230.128  # 監聽ip
port = 5678  # 端口

###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###

[loggers]
keys = root, myproject, sqlalchemy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_myproject]
level = DEBUG
handlers =
qualname = myproject

[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither.  (Recommended for production systems.)

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s

 初始化數據

initialize_[項目名稱]_db development.ini

存儲模型設計

model.py

class Users(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)  # Column固定用法
    name = Column(Unicode(255), unique=True)
    password = Column(Unicode(255))
    email = Column(Unicode(255), unique=True)
    group_id = Column(Integer)

    def __init__(self, name, password, email, group_id):
        self.name = name
        self.password = password
        self.email = email
        self.group_id = group_id

 注冊到initializedb.py中

import os
import sys
import transaction

from sqlalchemy import engine_from_config

from pyramid.paster import (
    get_appsettings,
    setup_logging,
    )

from ..models import (
    DBSession,
    MyModel,
    Users,
    Base,
    )


def usage(argv):
    cmd = os.path.basename(argv[0])
    print('usage: %s <config_uri>\n'
          '(example: "%s development.ini")' % (cmd, cmd))
    sys.exit(1)


def main(argv=sys.argv):
    if len(argv) != 2:
        usage(argv)
    config_uri = argv[1]
    setup_logging(config_uri)
    settings = get_appsettings(config_uri)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)
    with transaction.manager:
        # model = MyModel(name='one', value=1)
        # DBSession.add(model)
        admin = Users()
        admin.name = 'admin'
        admin.password = 'admin'
        admin.email = '88983860@qq.com'
        DBSession.add(admin)

刪除原來的devdata.db,重新初始化數據庫

 數據存儲類型設計

多對多,多表關聯

自關聯

# -*- coding:UTF-8 -*-
from datetime import datetime
from sqlalchemy import (
    Table,          # 創建關聯表的時候要導入
    Column,
    ForeignKey,     # 引用外鍵
    Integer,        # 整型
    Text,           # 文本類型
    Unicode,        # Unicode類型
    DateTime,       # 時間類型
    Float,          # 浮點型
    )

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
    relationship,  # 引用關聯數據
    )

from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()


class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)  # primary_key 主鍵
    name = Column(Unicode(255), nullable=False, unique=True)  # nullable=False
                                                              # 不允許為空 unique 唯一
    password = Column(Unicode(255), nullable=False)
    email = Column(Unicode(255), unique=True)
    group_id = Column(Integer, ForeignKey('groups.id'), nullable=False)  # 關聯外鍵groups的id
    group = relationship('Group', backref='users')
    # 可以使用User的實例對象+".group"查詢Group的數據,\
    #  backref可以使用Group的實例對象查詢User的數據,\
    # 以列表形式返回 相當於在Group里寫users = relationship('User')

# 創建關聯中間表
# 中間表 = Table(表名, Base.metadata,字段1,字段2....)
# Base.metadata 固定用法
group_permisson = Table('group_permission', Base.metadata,
    Column('group_id', Integer, ForeignKey('groups.id'), primary_key=True),  # 字段前要加字段名稱
    Column('permission_id', Integer, ForeignKey('permissions.id'),
           primary_key=True)
                        )

class Group(Base):
    __tablename__ = 'groups'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255), nullable=False)

    permission = relationship('Permission', secondary='group_permission', # 從表關聯
                              backref='groups')

class Permission(Base):
    __tablename__ = 'permissions'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255), nullable=False)

class Item(Base):
    __tablename__ = 'items'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255), nullable=False, unique=True)
    description = Column(Text)
    price = Column(Float, nullable=False, default=0.00)

    category_id = Column(Integer, ForeignKey('categories.id'), nullable=False)
    category = relationship('Category', backref='items')

class Category(Base):
    __tablename__ = 'categories'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255), nullable=False, unique=True)
    parent_id = Column(Integer, ForeignKey('categories.id'), nullable=True)
    parent = relationship('Category', remote_side=[id],   # 外鍵是自己的時候需要加入remote_side
                          backref='children')

class ItemImage(Base):
    __tablename__ = 'images'
    id = Column(Integer, primary_key=True)
    path = Column(Unicode(255), nullable=False)
    item_id = Column(Integer, ForeignKey('items.id'), nullable=False)
    item = relationship('Item', backref='images')

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    user = relationship('User', backref='comments')
    item_id = Column(Integer, ForeignKey('items.id'), nullable=False)
    item = relationship('Item', backref='comments')

    rank = Column(Integer, nullable=False, default=3)
    content = Column(Text)

cart_item = Table('cart_item', Base.metadata,
    Column('cart_id', Integer, ForeignKey('carts.id'), primary_key=True),
    Column('item_id', Integer, ForeignKey('items.id'), primary_key=True)
                  )

class Cart(Base):
    __tablename__ = 'carts'
    id = Column(Integer, primary_key=True)

    items = relationship('Item', secondary='cart_item')
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    user = relationship('User', backref='cart')

order_item = Table('order_item', Base.metadata,
    Column('order_id', Integer, ForeignKey('orders.id'), primary_key=True),
    Column('item_id', Integer, ForeignKey('items.id'), primary_key=True)
               )

class Order(Base):
    __tablename__ = 'orders'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    user = relationship('User')

    items = relationship('Item', secondary='order_item')
    add_time = Column(DateTime, nullable=False, default=datetime.now())
    address = Column(Unicode(255), nullable=False)
    telephone = Column(Unicode(25), nullable=False)

 配置路由

 

 __init__.py

# -*- coding:UTF-8 -*-
from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import (
    DBSession,
    Base,
    )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.add_static_view('static', 'static', cache_max_age=3600)  # 靜態資源
    config.add_route('home', '/')  # url映射 對應home主頁
    config.add_route('category', '/category')  # url映射 對應category頁面
    config.scan()
    return config.make_wsgi_app()

視圖函數views.py函數中

# -*- coding:UTF-8 -*-
from pyramid.response import Response
from pyramid.view import view_config


from .models import (
    DBSession,
    )


@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
    # try:
    #     one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
    # except DBAPIError:
    #     return Response(conn_err_msg, content_type='text/plain', status_int=500)
    return {'one': 'one', 'project': '我是天才'}


@view_config(route_name='category', renderer='string')  # route_name對應__init__.py中的config.add_route('category', '/category')
def category_view(request):
    return 'This is category!'

使用視圖類view_defaults

創建views文件夾

 

 創建base.py文件

import logging
from pyramid.httpexceptions import HTTPFound, HTTPBadRequest, HTTPServerError, \
    HTTPForbidden, HTTPUnauthorized
import json

log = logging.getLogger(__name__)


class Base(object):
    def __init__(self, request):
        self.request = request


class CBase(Base):
    def __init__(self, request):
        Base.__init__(self, request)

創建視圖控制器categories.py

# -*- coding:UTF-8 -*-
from pyramid.response import Response
from pyramid.view import view_config, view_defaults from myshop.lib import category  # 引用category數據文件 from base import CBase

ctrl = 'categories'

# @view_config(route_name='home', renderer='templates/mytemplate.pt')
@view_defaults(route_name='/')  # url映射對應__init__.py中的config.add_route('/', '/{ctrl}/{action}') class categories(CBase):
    def __init__(self, request):
        CBase.__init__(self, request)
        self.request.title = '分類'

    @view_config(match_param=('ctrl=%s' % ctrl, 'action=view'),  # 對應控制器文件和方法
                 renderer="mytemplate.html")
    def view(request):
        category_list = category.get_category_list()
        return {'one': 'one', 'project': category_list}

__init__.py文件中修改路由

# -*- coding:UTF-8 -*-
from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from myshop.models import (
    DBSession,
    Base,
    )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.add_renderer(".html", 'pyramid.mako_templating.renderer_factory')
    config.add_static_view('static', 'static', cache_max_age=3600)  # 靜態資源
    # config.add_route('home', '/')  # url映射 對應home主頁
    # config.add_route('category', '/category')  # url映射 對應category頁面
    config.add_route('/', '/{ctrl}/{action}')  # url映射 對應category頁面
    config.scan()
    return config.make_wsgi_app()
帶參數路由

配置url映射

config.add_route('/', '/{ctrl}/{action}/{id}')  # url映射 攜帶id參數

視圖函數views/item.py中接收參數

# -*- coding:UTF-8 -*-
from pyramid.response import Response
from pyramid.view import view_config, view_defaults
from myshop.lib import category
from base import CBase

ctrl = 'item'

# @view_config(route_name='home', renderer='templates/mytemplate.pt')
@view_defaults(route_name='/')
class item(CBase):
    def __init__(self, request):
        CBase.__init__(self, request)
        self.request.title = '商品'

    @view_config(match_param=('ctrl=%s' % ctrl, 'action=view'),
                 renderer="item.html")
                 # renderer="string")
    def view(self):
        id = self.request.matchdict.get('id')  # 接收id
        result = {}
        result['id'] = id
        return result

渲染到模板item.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>${id}</h1>
</body>
</html>

 

模板引擎換成mako以及后綴換成'.html'

1. 在配置文件development.ini中,添加上:

mako.directories = [project name]:[root path]

mako.directories = myshop:templates  # 更改為mako模板 mako.directories = [project name]:[root path] 項目名:html文件目錄
mako.strict_undefined = true

project name是你項目的名稱

root path 是你模板文件存放的根目錄

跟多關於mako的設置: https://pyramid.readthedocs.io/en/1.3-branch/narr/environment.html#mako-template-render-settings

2. 修改項目的__init__.py文件,在main函數中添加上:

config.add_renderer('.html', 'pyramid.mako_templating.renderer_factory')

凡是使用.html結尾的模板,都會使用mako引擎

3. 當在View.py中,使用.html的模板,就會使用mako模板引擎了。

@view_config(match_param=('ctrl=%s' % ctrl, 'action=view'),
                 renderer="mytemplate.html")
    def view(request):
        # try:
        #     one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
        # except DBAPIError:
        #     return Response(conn_err_msg, content_type='text/plain', status_int=500)
        return {'one': 'one', 'project': 'TTTTT'}

 出錯

File "/home/python/.virtualenvs/pyramid_py2/local/lib/python2.7/site-packages/mako/lookup.py", line 263, in get_template
    "Cant locate template for uri %r" % uri
TopLevelLookupException: Cant locate template for uri 'mytemplate.html'

development.int文件里mako配置的時候不能在后面加注釋

mako.directories = myshop:templates  # 更改為mako模板 mako.directories = [project name]:[root path] 項目名:html文件目錄

導致找不到模板

# 更改為mako模板 mako.directories = [project name]:[root path] 項目名:html文件目錄
mako.directories = myshop:templates

解決

認證和權限

配置__init__.py

# -*- coding:UTF-8 -*-
from pyramid.config import Configurator
from pyramid.authentication import AuthTktAuthenticationPolicy  # 認證
from pyramid.authorization import ACLAuthorizationPolicy        # 權限
from pyramid.security import Allow
from sqlalchemy import engine_from_config
from myshop.lib import user
from myshop.models import (
    DBSession,
    Base,
    )

def groupfinder(userid, request):
    """每當用戶登錄的時候,每當認證機制檢查用戶是否存在時都會調用下這個函數"""
    print("*" * 100)
    user_info = user.get_user_by_id(userid)  # 查詢登錄賬戶信息
    if user_info:
        return [user.group.id]
    return None

class RootFactory(object):   # 創建RootFactory類
    def __init__(self, request):
        """讀取所有權限"""
        group_list = user.get_group_list()  # 查詢所有的組
        self.__acl__ = []  # 准備acl列表
        for group in group_list:
            for permission in group.permissions:
                # 給acl列表添加元祖,  1.Allow 允許或拒絕 需要導入Allow庫 2.為了不和其它id沖突 添加g:的標識符 3.權限名稱
                self.__acl__.append(
                    (Allow, 'g:' + str(group.id), permission.name)
                )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    # 權限和授權
    # 認證機制
     authn_policy = AuthTktAuthenticationPolicy(
                 'secret',  # 加密密鑰
                 callback = groupfinder,  # 用於查詢用戶屬於哪個用戶組,以及這個用戶是否存在
                 hashalg = 'sha512'  # hashalg算法,用什么方式進行加密
                    )

    # 授權機制
    authz_policy = ACLAuthorizationPolicy()

    # config = Configurator(settings=settings)
    # config配置里添加權限
    config = Configurator(settings=settings, root_factory='myshop.RootFactory')
    # 添加認證機制到config
    config.set_authentication_policy(authn_policy)
    # 添加授權機制
    config.set_authorization_policy(authz_policy)

    config.add_renderer(".html", 'pyramid.mako_templating.renderer_factory')
    config.add_static_view('static', 'static', cache_max_age=3600)  # 靜態資源
    # config.add_route('home', '/')  # url映射 對應home主頁
    # config.add_route('category', '/category')  # url映射 對應category頁面
    config.add_route('/', '/{ctrl}/{action}*pa')  # url映射 對應控制器-方法 頁面
    config.add_route('index', '/{action:.*}')  # url映射 對應控制器-方法 頁面
    config.scan()
    return config.make_wsgi_app()

 

RootFactory要做的事

查出user.id ---> 通過user查出組 user.group.id -> 保存起來 save it

查出組的權限 group.permission ---->  對比視圖函數權限  view(permission=???)   檢查成功則說明有這個權限,繼續訪問這個視圖

RootFacory里就是要查出哪個組有哪個權限的信息,然后告訴pyramid這個框架

給item視圖加權限

# -*- coding:UTF-8 -*-
from pyramid.response import Response
from pyramid.view import view_config, view_defaults
from myshop.lib import category
from base import CBase

ctrl = 'item'

# @view_config(route_name='home', renderer='templates/mytemplate.pt')
@view_defaults(route_name='/')
class item(CBase):
    def __init__(self, request):
        CBase.__init__(self, request)
        self.request.title = u'商品'

    @view_config(match_param=('ctrl=%s' % ctrl, 'action=view'),
                 renderer="item.html", permission='item')
                 # renderer="string")
    def view(self):
        id = self.request.params.get('id')  # 接收id
        item_info = category.get_item_by_id(id)
        return {'item':item_info}

登錄有權限的賬號發現

 

 如圖:如果沒有添加商品得權限則不讓添加商品按鈕顯示

model.py中給user添加校驗方法

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)  # primary_key 主鍵
    name = Column(Unicode(255), nullable=False, unique=True)  # nullable=False
                                                              # 不允許為空 unique 唯一
    password = Column(Unicode(255), nullable=False)
    email = Column(Unicode(255), unique=True)
    group_id = Column(Integer, ForeignKey('groups.id'), nullable=False)  # 關聯外鍵groups的id
    group = relationship('Group', backref='users')
    # 可以使用User的實例對象+".group"查詢Group的數據,\
    #  backref可以使用Group的實例對象查詢User的數據,\
    # 以列表形式返回 相當於在Group里寫users = relationship('User')

    def has_permission(self, permission):
        # import pdb;pdb.set_trace()
        for perm in self.group.permissions:
            if perm.name == permission:
                return True
        return False

然后再視圖模板中調用該方法

<ul class="menu_r">
            <li><a href="${request.route_path('index', ctrl='', action='',pa=())}">首頁</a></li>
            % if request.title==u'分類':
                % if request.user.has_permission('item'):
                    <li><a href="#"  onclick="itemAdd()">添加商品</a></li>
                % endif
            % endif
        </ul>

 

單步調試

在需要調試的地方引用pdb;pdb_set_trace()

此處__init.py中的groupfinder方法需要調試

def groupfinder(userid, request):
    """每當用戶登錄的時候,每當認證機制檢查用戶是否存在時都會調用下這個函數"""
    import pdb;pdb.set_trace()
    user_info = user.get_user_by_id(userid)  # 查詢登錄賬戶信息
    if user_info:
        return [user_info.group.id]
    return None

登錄賬號然后查看終端

 

 此處可以打印下id等查看

也可以輸入n進行下一步,一步一步調試

 

調試后發現返回的只是一個用戶組的id,且id是整型 與RootFactory中__acl__定義的不一致

def groupfinder(userid, request):
    """每當用戶登錄的時候,每當認證機制檢查用戶是否存在時都會調用下這個函數"""
    print("*" * 100)
    user_info = user.get_user_by_id(userid)  # 查詢登錄賬戶信息
    if user_info:
        return [user.group.id]  # 與__acl__定義的標識符不一致
    return None

class RootFactory(object):   # 創建RootFactory類
    def __init__(self, request):
        """讀取所有權限"""
        group_list = user.get_group_list()  # 查詢所有的組
        self.__acl__ = []  # 准備acl列表
        for group in group_list:
            for permission in group.permissions:
                # 給acl列表添加元祖,  1.Allow 允許或拒絕 需要導入Allow庫 2.為了不和其它id沖突 添加g:的標識符 3.權限名稱
                self.__acl__.append(
                    (Allow, 'g:' + str(group.id), permission.name)  
                )

修改為

def groupfinder(userid, request):
    """每當用戶登錄的時候,每當認證機制檢查用戶是否存在時都會調用下這個函數"""
    # import pdb; pdb.set_trace()  # 斷點調試
    user_info = user.get_user_by_id(userid)  # 查詢登錄賬戶信息
    if user_info:
        return ['g:' + str(user_info.group.id)]  # 與__acl__定義的標識符保持一致
    return None

可以進入頁面了

 登錄時把user信息存入request

__init__.py配置config

def get_user(request):
    user_id = unauthenticated_userid(request)
    user_info = user.get_user_by_id(user_id)
    return user_info

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    .
    .
    .
     # 添加授權機制
    config.set_authorization_policy(authz_policy)
    # 添加用戶信息到request
    config.set_request_property(get_user,  # 回調函數
                                'user',   # 此處寫user就是request.user 寫u就是request.u
                                reify=True)  # 為True的時候會把登錄用戶保存下來 不需要每次區查詢

 html模板里用request.user渲染數據

<span  class="fl">
         ${request.user.name},歡迎您的到來
</span>

 DBSession存入request

# 添加DBSession到request
    config.set_request_property(lambda request: DBSession,
                                'db',
                                reify=True)

用的時候需要傳入request

def get_category_list(request):
    result = request.db.query(Category).filter_by(parent=None).all()
    return result

 ValueError: renderer was passed non-dictionary as value:渲染器以非字典形式作為值傳遞

做添加商品頁面時出現錯誤

視圖函數中item.py

 @view_config(match_param=('ctrl=%s' % ctrl, 'action=item_add'),
                 renderer="itemadd.html")
    def item_add(self):

        category_id = self.request.params.get('category_id','')
        print(category_id)
        return category_id

 

 解決方法-使用字典傳值

 @view_config(match_param=('ctrl=%s' % ctrl, 'action=item_add'),
                 renderer="itemadd.html")
    def item_add(self):
        result = {}
        result['category_id'] = self.request.params.get('category_id', '')
        print(result)
        return result

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM