2012-11-02 28 views
6

Tôi đang viết trang web quản trị điều khiển một số trang web có cùng lược đồ cơ sở dữ liệu và chương trình nhưng có nội dung khác nhau. URL tôi thiết kế như thế này:Làm cách nào để xử lý URL phức tạp một cách thanh lịch?

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 

Như bạn có thể thấy, gần như tất cả URL đều cần site_id. Và trong hầu hết tất cả các khung nhìn, tôi phải thực hiện một số công việc phổ biến như mô hình truy vấn Site đối với cơ sở dữ liệu với site_id. Ngoài ra, tôi phải vượt qua site_id bất cứ khi nào tôi gọi request.route_path.

Vậy ... có cách nào để tôi làm cho cuộc sống của tôi dễ dàng hơn?

Trả lời

5

Có thể hữu ích khi bạn sử dụng phương pháp kết hợp để tải trang web.

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 

Chúng tôi sẽ sử dụng để lập bản đồ groupfinder người dùng hiệu trưởng. Chúng tôi đã chọn ở đây để chỉ lập bản đồ cho các trang web mà họ có tư cách thành viên bên trong. Quá trình truyền tải đơn giản của chúng tôi chỉ yêu cầu đối tượng gốc. Nó cập nhật các site được nạp với một __acl__ sử dụng cùng một hiệu trưởng mà groupfinder được thiết lập để tạo.

Bạn sẽ cần phải thiết lập các mẫu request.db được đưa ra trong Sách hướng dẫn kim tự tháp.

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 

Trình phát trước có thể tìm thấy site_id và tự động thêm URL đó vào URL cho bạn.

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

Chúng tôi thiết lập ứng dụng của mình tại đây. Chúng tôi cũng đã chuyển các tuyến đường thành một hàm có thể bao gồm, cho phép chúng tôi dễ dàng kiểm tra các tuyến đường hơn.

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

Quan điểm của chúng tôi sau đó được đơn giản hóa. Chúng chỉ được gọi nếu người dùng có quyền truy cập trang web và đối tượng trang web đã được tải cho chúng tôi.

lai Traversal

Một tùy chỉnh chỉ thị add_site_route được thêm vào để tăng cường đối tượng config của bạn với một wrapper xung quanh add_route mà sẽ tự động thêm hỗ trợ traversal vào tuyến đường. Khi tuyến đường đó phù hợp, nó sẽ lấy trình giữ chỗ {site_id} từ mẫu tuyến đường và sử dụng làm đường đi ngang của bạn (/{site_id} là đường dẫn mà chúng tôi xác định dựa trên cách cây có cấu trúc của chúng tôi được cấu trúc).

Sự cố xảy ra trên đường dẫn /{site_id} nơi bước đầu tiên tìm gốc của cây (/). Tuyến đường được thiết lập để thực hiện traversal bằng cách sử dụng SiteFactory làm gốc của đường dẫn truyền tải.Lớp này được khởi tạo là gốc, và __getitem__ được gọi với khóa là phân đoạn tiếp theo trong đường dẫn ({site_id}). Sau đó chúng tôi tìm thấy đối tượng trang web khớp với khóa đó và tải nó nếu có thể. Đối tượng trang web sau đó được cập nhật với __parent____name__ để cho phép find_interface hoạt động. Nó cũng được tăng cường với một số __acl__ cung cấp các quyền được đề cập sau.

Pregenerator

Mỗi tuyến đường được cập nhật với một pregenerator mà cố gắng để tìm ra thể hiện của Site trong hệ thống phân cấp traversal cho một yêu cầu. Điều này có thể thất bại nếu yêu cầu hiện tại không giải quyết được với URL dựa trên trang web. Trình tạo tiền tố sau đó cập nhật các từ khóa được gửi đến route_url với id trang web.

Xác thực

Ví dụ cho thấy cách bạn có thể có một chính sách xác thực mà bản đồ người dùng vào các hiệu trưởng chỉ ra rằng người dùng này nằm ở cùng "site:" nhóm. Trang web (request.context) sau đó được cập nhật để có ACL nói rằng nếu một người trong nhóm "site: 1" phải có quyền "xem". Sau đó, users_view được cập nhật để yêu cầu quyền "xem". Điều này sẽ tăng một ngoại lệ HTTPForbidden nếu người dùng bị từ chối truy cập vào chế độ xem. Bạn có thể viết một ngoại lệ xem để điều kiện dịch này thành một 404 nếu bạn muốn.

Mục đích của câu trả lời của tôi là chỉ cho thấy cách tiếp cận lai có thể làm cho số lượt xem của bạn đẹp hơn một chút bằng cách xử lý các phần phổ biến của URL trong nền. HTH.

+0

Vì sự rò rỉ của tôi về kiến ​​thức tra cứu của Kim tự tháp, tôi không thể hiểu rõ ví dụ của bạn nhưng tôi sẽ đọc tài liệu và cố gắng hiểu nó ... :-) BTW: Giải pháp của bạn có thể loại bỏ tham số 'site_id' khi tôi gọi yêu cầu .route_path? –

+1

Bạn có thể loại bỏ 'site_id' bằng cách thêm một bộ phát trước cho các tuyến tự động điền vào site_id khi một tuyến được tạo ra. Nó không rõ ràng, đó là lý do tại sao tôi đăng nó để kích thích sự thèm ăn của bạn. Nhưng quan điểm của bạn có thể trở nên khá đơn giản với một số cấu hình khai báo lên phía trước. –

+0

Tôi vẫn còn trong một mớ hỗn độn ..... Bạn có nhớ cập nhật ví dụ của mình với bộ phát trước mà bạn đã đề cập không? Cảm ơn! Nhân tiện, nếu tôi muốn thêm các tuyến khác nhau cho Site.type khác nhau, tôi phải làm gì? Ví dụ: nếu site1.type là 'hộ chiếu' và site1.id là 1, site2.type là 'www' và site2.id là 2 thì/site/1/người dùng phải được ánh xạ tới chế độ xem, nhưng/site/2/người dùng nên tăng lỗi 404. –

3

Đối với các quan điểm, bạn có thể sử dụng một lớp để công việc chung có thể được thực hiện trong __init__ phương pháp (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) 

Và bạn có thể sử dụng một tiền tố tuyến đường để xử lý các URL (docs) . Bạn không chắc chắn liệu điều này có hữu ích cho hoàn cảnh của bạn hay không.

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

Cảm ơn sự giúp đỡ của bạn! tiền tố tuyến đường là cách tôi đã sử dụng để sắp xếp URL của mình. Đặt quan điểm trong một lớp học thực sự là một ý tưởng tuyệt vời. Nhưng làm thế nào về route_path/route_url? Tôi vẫn phải vượt qua site_id mọi lúc. –

+0

Bạn có thể làm cho nó dễ dàng hơn một chút bằng cách thêm một phương thức vào lớp để làm điều này. Tôi đã cập nhật ví dụ của tôi với một ví dụ. – grc

Các vấn đề liên quan