Przydałaby się metoda hybrydowa w celu załadowania witryny.
def groupfinder(userid, request):
user = request.db.query(User).filter_by(id=userid).first()
if user is not None:
# somehow get the list of sites they are members
sites = user.allowed_sites
return ['site:%d' % s.id for s in sites]
class SiteFactory(object):
def __init__(self, request):
self.request = request
def __getitem__(self, key):
site = self.request.db.query(Site).filter_by(id=key).first()
if site is None:
raise KeyError
site.__parent__ = self
site.__name__ = key
site.__acl__ = [
(Allow, 'site:%d' % site.id, 'view'),
]
return site
Będziemy używać groupfinder do mapowania użytkowników do zleceniodawców. Wybraliśmy tutaj, aby mapować je tylko na strony, do których mają członkostwo. Nasze proste przejście wymaga tylko obiektu głównego. Aktualizuje załadowany site
z __acl__
, który używa tych samych zleceń, aby utworzyć konfigurację groupfinder
.
Musisz ustawić podane wzory w Piramidzie Cookbook.
def site_pregenerator(request, elements, kw):
# request.route_url(route_name, *elements, **kw)
from pyramid.traversal import find_interface
# we use find_interface in case we improve our hybrid traversal process
# to take us deeper into the hierarchy, where Site might be context.__parent__
site = find_interface(request.context, Site)
if site is not None:
kw['site_id'] = site.id
return elements, kw
Pregenerator można znaleźć site_id
i dodać go do adresów URL automatycznie.
def add_site_route(config, name, pattern, **kw):
kw['traverse'] = '/{site_id}'
kw['factory'] = SiteFactory
kw['pregenerator'] = site_pregenerator
if pattern.startswith('/'):
pattern = pattern[1:]
config.add_route(name, '/site/{site_id}/' + pattern, **kw)
def main(global_conf, **settings):
config = Configurator(settings=settings)
authn_policy = AuthTktAuthenticationPolicy('seekrit', callback=groupfinder)
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(ACLAuthorizationPolicy())
config.add_directive(add_site_route, 'add_site_route')
config.include(site_routes)
config.scan()
return config.make_wsgi_app()
def site_routes(config):
config.add_site_route('site_users', '/user')
config.add_site_route('site_items', '/items')
Tutaj konfigurujemy naszą aplikację. Przenieśliśmy również trasy do funkcji włączalnej, która pozwoli nam łatwiej testować trasy.
@view_config(route_name='site_users', permission='view')
def users_view(request):
site = request.context
Nasze poglądy są następnie uproszczone. Są one wywoływane tylko wtedy, gdy użytkownik ma uprawnienia dostępu do witryny, a obiekt witryny jest już załadowany dla nas.
Hybrid przemierzania
Niestandardowy dyrektywa add_site_route
jest dodawany w celu zwiększenia obiekt config
z obwolutą wokół add_route
który będzie automatycznie dodać wsparcie przejścia do trasy. Po dopasowaniu tej trasy, pobierze ona symbol zastępczy {site_id}
ze wzoru trasy i użyje go jako ścieżki przejścia (/{site_id}
to ścieżka, którą definiujemy na podstawie struktury naszego drzewa traversal).
Traversal dzieje się na ścieżce /{site_id}
, gdzie pierwszym krokiem jest znalezienie katalogu głównego drzewa (/
). Trasa jest skonfigurowana do wykonywania przemierzania przy użyciu SiteFactory
jako katalogu głównego ścieżki.Ta klasa jest tworzona jako root, a __getitem__
jest wywoływany za pomocą klucza, który jest następnym segmentem w ścieżce ({site_id}
). Następnie znajdujemy obiekt lokacji pasujący do tego klucza i ładujemy go, jeśli to możliwe. Obiekt witryny jest następnie aktualizowany za pomocą __parent__
i __name__
, aby umożliwić działanie find_interface
. Zostało również ulepszone poprzez zapewnienie uprawnień wymienionych poniżej.
Pregenerator
Każda trasa jest aktualizowana z pregenerator który próbuje znaleźć instancję Site
w hierarchii traversal dla wniosku. Może to się nie powieść, jeśli bieżące żądanie nie rozwiąże problemu z adresem URL witryny. Pregenerator następnie aktualizuje słowa kluczowe wysłane do route_url
z identyfikatorem witryny.
Authentication
Przykład pokazuje, jak można mieć politykę uwierzytelniania, która odwzorowuje użytkownika do zleceniodawców wskazujących, że ta osoba jest w „site:” grupy. Witryna (request.context
) jest następnie aktualizowana, aby mieć listę ACL mówiącą, że jeśli site.id == 1
ktoś z grupy "site: 1" powinien mieć uprawnienie "widok". Aktualizacja users_view
wymaga uprawnienia "zobacz". Spowoduje to zgłoszenie wyjątku HTTPForbidden
, jeśli użytkownik nie ma dostępu do widoku. Możesz napisać widok wyjątku, aby warunkowo przetłumaczyć go na 404, jeśli chcesz.
Celem mojej odpowiedzi jest pokazanie, jak podejście hybrydowe może sprawić, że poglądy będą odrobinę przyjemniejsze dzięki obsłudze części wspólnych adresu URL w tle. HTH.
Z powodu mojej nieszczelności wiedzy Pyramid, nie mogę w pełni zrozumieć twojego przykładu, ale przeczytam dokumenty i spróbuję to zrozumieć ... :-) BTW: Czy twoje rozwiązanie może wyeliminować parametr "site_id", gdy wezwę żądanie .route_path? –
Możesz wyeliminować 'site_id', dodając pregenerator do tras, które wypełniają identyfikator site_id automatycznie podczas generowania trasy. To nie jest oczywiste, dlatego napisałem to, by zaostrzyć twój apetyt. Ale twoje poglądy mogą stać się całkiem proste, z pewną deklaratywną konfiguracją z góry. –
Nadal jestem w bałaganie ... Czy masz ochotę zaktualizować swój przykład tym pregeneratorem, o którym wspomniałeś? Dzięki! Przy okazji, jeśli chcę dodać różne trasy dla różnych Site.type, co powinienem zrobić? Na przykład, jeśli site1.type to "paszport", a site1.id to 1, site2.type to "www", a site2.id to 2 to/site/1/użytkownik powinien zostać zmapowany do widoku, ale/site/2/użytkownik powinien zgłosić błąd 404. –