2012-11-02 21 views
6

मैं एक व्यवस्थापक वेबसाइट लिख रहा हूं जो एक ही प्रोग्राम और डेटाबेस स्कीमा के साथ कई वेबसाइटों को नियंत्रित करता है लेकिन विभिन्न सामग्री। यूआरएल मैं इस तरह तैयार किया गया है:जटिल यूआरएल को सुरुचिपूर्ण तरीके से कैसे संभालें?

http://example.com/site     A list of all sites which under control 
http://example.com/site/{id}   A brief overview of select site with ID id 
http://example.com/site/{id}/user  User list of target site 
http://example.com/site/{id}/item  A list of items sold on target site 
http://example.com/site/{id}/item/{iid} Item detailed information 
# ...... something similar 

आप देख सकते हैं, लगभग सभी यूआरएल site_id की जरूरत है। और लगभग सभी विचारों में, मुझे साइट_आईडी के साथ डेटाबेस के खिलाफ क्वेरी साइट मॉडल जैसी कुछ सामान्य नौकरियां करना है। साथ ही, जब भी मैं request.route_path का आह्वान करता हूं, मुझे साइट_आईडी पास करना होगा।

तो ... क्या मेरे जीवन को आसान बनाने के लिए वैसे भी है?

उत्तर

5

साइट लोड होने के लिए हाइब्रिड दृष्टिकोण का उपयोग करना आपके लिए उपयोगी हो सकता है।

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 

हम प्रिंसिपलों के लिए उपयोगकर्ताओं को मैप करने के लिए groupfinder का उपयोग करेंगे। हमने यहां उन्हें केवल उन साइटों पर मैप करने के लिए चुना है जिनके पास उनकी सदस्यता है। हमारे सरल ट्रैवर्सल को केवल रूट ऑब्जेक्ट की आवश्यकता होती है। यह को __acl__ के साथ लोड किया गया है जो groupfinder बनाने के लिए एक ही प्रिंसिपल का उपयोग करता है।

आपको पिरामिड कुकबुक में request.db दिए गए पैटर्न सेट अप करने की आवश्यकता होगी।

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 site_id खोजने के लिए और अपने आप आपके लिए यूआरएल में जोड़ सकते हैं।

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') 

हम यहां अपना आवेदन सेट अप करते हैं। हमने मार्गों को एक समावेशी समारोह में भी स्थानांतरित किया जो हमें मार्गों का अधिक आसानी से परीक्षण करने की अनुमति दे सकता है।

@view_config(route_name='site_users', permission='view') 
def users_view(request): 
    site = request.context 

हमारे विचार तब सरलीकृत किए जाते हैं। उन्हें केवल तभी बुलाया जाता है जब उपयोगकर्ता को साइट तक पहुंचने की अनुमति हो, और साइट ऑब्जेक्ट पहले से ही हमारे लिए लोड हो चुका है।

हाइब्रिड Traversal

एक कस्टम निर्देश add_site_route जो स्वत: मार्ग के लिए ट्रेवर्सल समर्थन जोड़ देगा add_route के चारों ओर एक आवरण के साथ अपने config वस्तु को बढ़ाने के लिए जोड़ा गया है। जब उस मार्ग का मिलान किया जाता है, तो यह मार्ग पैटर्न से {site_id} प्लेसहोल्डर ले जाएगा और इसका उपयोग करेगा क्योंकि आपके ट्रैवर्सल पथ (/{site_id} पथ है जिसे हम परिभाषित करते हैं कि हमारे ट्रैवर्सल पेड़ को कैसे संरचित किया जाता है)।

ट्रैवर्सल पथ /{site_id} पर होता है जहां पहला चरण पेड़ की जड़ (/) ढूंढ रहा है। मार्ग SiteFactory का उपयोग ट्रैवर्सल पथ की जड़ के रूप में ट्रैवर्सल करने के लिए किया गया है।इस वर्ग को रूट के रूप में तुरंत चालू किया गया है, और __getitem__ को उस कुंजी के साथ बुलाया जाता है जो पथ में अगला खंड है ({site_id})। फिर हमें उस साइट से मिलान करने वाली साइट ऑब्जेक्ट मिलती है और यदि संभव हो तो इसे लोड करें। find_interface को काम करने की अनुमति देने के लिए साइट ऑब्जेक्ट को __parent__ और __name__ के साथ अपडेट किया गया है। इसे __acl__ के साथ बाद में वर्णित अनुमतियां प्रदान करने के साथ भी बढ़ाया गया है।

Pregenerator

प्रत्येक मार्ग एक pregenerator है कि एक अनुरोध के लिए ट्रेवर्सल पदानुक्रम में Site का उदाहरण खोजने के लिए प्रयास करता है के साथ अद्यतन किया जाता है। यदि वर्तमान अनुरोध साइट-आधारित यूआरएल को हल नहीं करता है तो यह असफल हो सकता है। प्रीजेनरेटर साइट आईडी के साथ route_url पर भेजे गए कीवर्ड अपडेट करता है।

प्रमाणीकरण

उदाहरण दिखाता है कि आप एक प्रमाणीकरण नीति है जो यह दर्शाता है कि इस प्रयोक्ता "साइट:" में है प्रधानाचार्यों, जो उपयोगकर्ता को नक्शे हो सकता है समूह। साइट (request.context) को तब एसीएल कहने के लिए अपडेट किया गया है कि अगर site.id == 1 "साइट: 1" समूह में से किसी को "दृश्य" अनुमति होनी चाहिए। users_view को तब "दृश्य" अनुमति की आवश्यकता के लिए अद्यतन किया जाता है। यदि उपयोगकर्ता को दृश्य तक पहुंच से वंचित कर दिया गया है तो यह HTTPForbidden अपवाद उठाएगा। यदि आप चाहें तो 404 में सशर्त रूप से इसका अनुवाद करने के लिए आप एक अपवाद दृश्य लिख सकते हैं।

मेरे उत्तर का उद्देश्य यह दिखाने के लिए है कि कैसे एक हाइब्रिड दृष्टिकोण पृष्ठभूमि में एक यूआरएल के सामान्य भागों को संभालने से आपके विचारों को थोड़ा अच्छा बना सकता है। HTH।

+0

पिरामिड के ट्रैवर्सल ज्ञान के मेरे रिसाव के कारण, मैं आपका उदाहरण पूरी तरह से समझ नहीं पा रहा हूं लेकिन मैं दस्तावेज़ों को पढ़ूंगा और इसे समझने की कोशिश करूंगा ... :-) बीटीडब्ल्यू: जब मैं अनुरोध करता हूं तो आपका समाधान 'site_id' पैरामीटर को खत्म कर सकता है .route_path? –

+1

जब आप मार्ग उत्पन्न होते हैं तो साइट_आईडी में स्वचालित रूप से भरने वाले मार्गों पर प्रीजेनरेटर जोड़कर आप 'site_id' को समाप्त कर सकते हैं। यह स्पष्ट नहीं है, यही कारण है कि मैंने इसे अपनी भूख लगी है। लेकिन आपके विचार कुछ घोषणात्मक कॉन्फ़िगरेशन के साथ बहुत सरल हो सकते हैं। –

+0

मैं अभी भी एक गड़बड़ में हूं ..... क्या आप इस उदाहरण के साथ अपना उदाहरण अपडेट करते हैं? धन्यवाद! वैसे, अगर मैं विभिन्न साइट के लिए अलग-अलग मार्ग जोड़ना चाहता हूं। टाइप, मैं क्या करूँ? उदाहरण के लिए, यदि site1.type 'पासपोर्ट' है और site1.id 1 है, site2.type 'www' है और site2.id 2 है/साइट/1/उपयोगकर्ता को देखने के लिए मैप किया जाना चाहिए, लेकिन/साइट/2/उपयोगकर्ता को 404 त्रुटि उठानी चाहिए। –

3

विचारों के लिए, आप एक वर्ग इस्तेमाल कर सकते हैं, ताकि आम नौकरियों __init__ विधि (docs) में किया जा सकता है:

from pyramid.view import view_config 

class SiteView(object): 
    def __init__(self, request): 
     self.request = request 
     self.id = self.request.matchdict['id'] 
     # Do any common jobs here 

    @view_config(route_name='site_overview') 
    def site_overview(self): 
     # ... 

    @view_config(route_name='site_users') 
    def site_users(self): 
     # ... 

    def route_site_url(self, name, **kw): 
     return self.request.route_url(name, id=self.id, **kw) 

और आप यूआरएल को संभालने के लिए एक मार्ग उपसर्ग इस्तेमाल कर सकते हैं (docs) । सुनिश्चित नहीं है कि यह आपकी स्थिति के लिए उपयोगी होगा या नहीं।

from pyramid.config import Configurator 

def site_include(config): 
    config.add_route('site_overview', '') 
    config.add_route('site_users', '/user') 
    config.add_route('site_items', '/item') 
    # ... 

def main(global_config, **settings): 
    config = Configurator() 
    config.include(site_include, route_prefix='/site/{id}') 
+0

आपकी मदद के लिए धन्यवाद! मार्ग उपसर्ग जिस तरह से मैंने पहले ही अपना यूआरएल व्यवस्थित करने के लिए उपयोग किया है। कक्षा में विचारों को वास्तव में एक शानदार विचार है। लेकिन path_path/path_url के बारे में कैसे? मुझे अभी भी साइट_आईडी को हर बार पास करना होगा। –

+0

ऐसा करने के लिए कक्षा में एक विधि जोड़कर आप इसे थोड़ा आसान बना सकते हैं। मैंने एक उदाहरण के साथ अपना उदाहरण अपडेट किया है। – grc