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>
'
'(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
總結
以上是生活随笔為你收集整理的pyramid基本用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国字脸带牙套可以改变脸型吗
- 下一篇: 十、Compose命令