2010-11-20 39 views
11

Tôi đã làm việc với Django một thời gian (hiện tại trên phiên bản 1.2), nhưng gần đây đã bắt đầu làm việc trên một ứng dụng cần hỗ trợ nhiều phiên bản. Ví dụ, hồ sơ dự án urls.py sẽ bao gồm nó hai lần, dưới hai namespaces khác nhau, như thế này:Đảo ngược URL không gian tên trong Django: nhiều phiên bản của cùng một ứng dụng

urlpatterns = patterns('', 
    (r'^instance1/', include('myapp.urls', namespace='instance1')), 
    (r'^instance2/', include('myapp.urls', namespace='instance2')), 
) 

tôi đã đi cùng tốt, cho đến khi tôi nhận ra tôi cần thiết để tìm ra những việc cần làm về tất cả các cuộc gọi nội bộ để reverse() (hoặc mẫu gọi tới bộ lọc {% url %}). Ví dụ, giả sử tôi đang làm một cái gì đó như sau trong một trong những quan điểm của tôi:

return HttpResponseRedirect(reverse('view_name')) 

hoặc một cái gì đó như thế này trong một trong các mẫu của tôi:

<a href="{% url view_name %}">link text</a> 

... nơi view_name là tên của mẫu URL có trong myapp.urls. Vì tôi đang sử dụng không gian tên, điều này sẽ gây ra lỗi: không có chế độ xem nào được gọi là view_name. Thay vào đó, tôi phải nói điều đó là instance1:view_name hoặc instance2:view_name. Nhưng làm điều này năng động là stumping tôi.

tôi đã làm một số tìm kiếm và nó trông giống như current_app cãi nhau, truyền cho một trong hai Context hoặc RequestContext, được thiết kế để giúp đỡ với điều này, nhưng nó không phải là rõ ràng ở tất cả các cách để tự động vượt qua các tên ứng dụng đúng-current_app. Vì vậy, những gì đúng cách để nói với Django mà không gian tên để sử dụng?

EDIT: Trường hợp sử dụng của tôi là sử dụng một lần cài đặt ứng dụng nhiều lần. Đó là, nó chỉ tồn tại trên đĩa một lần, nhưng được bao gồm nhiều lần trong gốc của dự án urls.py (mỗi lần theo một không gian tên khác nhau, như trong ví dụ của tôi ở trên). Với điều này trong tâm trí, có cách nào tốt để theo dõi không gian tên một khung nhìn/mẫu được gọi là từ, và làm cho bất kỳ sử dụng reverse() hoặc {% url %} dính trong cùng một không gian tên? Tôi biết Django 1.3 sẽ cung cấp một số tính năng bổ sung có thể giúp với điều này (cụ thể là, new and improved resolve()), nhưng chắc chắn có một cách hay để làm điều này ngay bây giờ ...

+1

Câu trả lời của tôi cho http://stackoverflow.com/questions/2030225/how-to-get-current-app-for-using-with-reverse-in-multi-deployable-reusable-djang/13249060#13249060 áp dụng ở đây là tốt. – stefanfoulis

Trả lời

3

Không phải là một giải pháp rất tốt đẹp, nhưng kể từ khi bạn sử dụng văn bản tương tự cho không gian tên của bạn và một phần ban đầu của Đường dẫn URL, bạn có thể trích xuất phần tử đó từ request.path (request.path.split('/')[1]) và đặt thành current_app trong ngữ cảnh yêu cầu hoặc chỉ sử dụng nó làm không gian tên trong chế độ xem.

http://docs.djangoproject.com/en/dev/topics/http/urls/#url-namespaces điểm 2.

Bạn có thể làm điều đó ví dụ trong một bộ xử lý ngữ cảnh (nếu bạn muốn sử dụng không gian tên trong một khuôn mẫu).

Đối với quan điểm bạn có thể viết một trang trí mà nguồn cấp dữ liệu chức năng của bạn một kwarg thêm "namespace" và sử dụng nó như:

@feed_namespace 
def view1(request, *args, **kwargs): 
    ns = kwargs['namespace'] 

hoặc chỉ cần viết một hàm reverse_namespaced với một param thêm (theo yêu cầu), nơi các chức năng lấy không gian tên từ và sử dụng nó thay vì đảo ngược.

Tất nhiên nếu bạn làm điều này bạn sẽ luôn luôn phải sử dụng một yêu cầu path/namespace cho ứng dụng này

+0

Cảm ơn, ý tưởng đầu tiên (sử dụng một phần của đường dẫn để lấy không gian tên) là gì Tôi đã kết thúc. Nếu tôi cần phải làm điều này một lần nữa trước khi 1.3 đi ra, ý tưởng khác của bạn có thể rất hữu ích. – mjjohnson

2

Có một trang doc về đảo ngược url không gian tên.

http://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-reversing-url-namespaces

Hoặc reverse('instance1:myapp.urls.some_view') hoặc reverse('instance1:view_name') nên làm việc, hoặc cả hai :) - Tôi đã không bao giờ cố gắng này bản thân mình.

+4

Những thứ đó sẽ hoạt động, đúng - nhưng sau đó sẽ khó mã hóa ứng dụng để chỉ làm việc với các giá trị cụ thể cho không gian tên. Tôi muốn ứng dụng không quan tâm đến không gian tên nào được gán trong tệp urls.py chính của người dùng: nó sẽ tự động sử dụng tên miền 'đúng', điều chỉnh tùy thuộc vào không gian tên mà chế độ xem được gọi từ (hoặc mẫu nào đang được hiển thị) . – mjjohnson

2

Biến số current_app là thứ bạn phải đặt cho chính mình cho thứ bạn thích.

Cá nhân tôi khuyên bạn nên đặt nó thành một cái gì đó như __name__.rsplit('.', 1)[0] để bạn có được spam trong spam/views.py.

Nhưng bạn có thể xác định nó là bất cứ thứ gì bạn thích, miễn là tên ứng dụng của bạn nhất quán với những gì bạn xác định trong tệp url.

+0

Hm, có lẽ tôi đề cập đến current_app là một cá trích đỏ. Giả sử tôi đang sử dụng cùng một ứng dụng (cùng một tệp views.py, v.v.) nhưng nhập cùng một tệp app/urls.py hai lần (hai tệp khác nhau bao gồm trong tệp urls.py của dự án, dưới hai không gian tên, như trong ví dụ ở trên), có cách nào để tự động nhận các cuộc gọi 'reverse()' và '{% url%}' của mình để gắn với cùng một không gian tên mà chúng đang được gọi không? – mjjohnson

+0

@peppergrower: không xa như tôi biết. Tôi đã chọn tự thêm không gian tên cho bản thân 'đảo ngược' và' {% url%} '. Tiết kiệm một chút rắc rối. Nó sẽ là tầm thường để bọc 'render_to_response' và' đảo ngược' với một phiên bản bao gồm bạn 'current_app' mặc dù. Một cái gì đó như thế này có thể đủ: 'reverse = lambda * a, ** kw: original_reverse (current_app = YOUR_CURRENT_APP, * a, ** kw)' – Wolph

1

Nếu bạn không quá gắn liền với không gian tên, bạn thay vì có thể viết urls.py của bạn trở nên giống như:

urlpatterns = patterns('', 
    (r'^(P<instance>/)', 'controllers.route_me'), 
) 

này sẽ thực hiện cuộc gọi đến các bộ điều khiển.chức năng route_me và vượt qua nó yêu cầu, cộng với chuỗi 'dụ', mà bạn có thể xử lý theo cách này:

# (in controllers.py) 
def route_me(request, instance): 
    # you now have complete control, and do what you need to do with the 'instance' and 'request' vars 
    pass 
4

Rất nhiều đã thay đổi kể từ khi câu hỏi đã được đăng nhưng đối với nhân viên của Google trong tương lai (như bản thân mình) nó có thể là hữu ích để chỉ ra rằng request có namespace bây giờ (ít nhất từ ​​1,7 như trong this example.

Từ những gì tôi hiểu, chúng tôi sẽ có thể chỉ đơn giản là vượt qua current_app luận vị trí để reverse/redirect nhưng tôi không thể làm cho nó làm việc như vậy Tôi đã kết thúc việc tạo phương thức trợ giúp cho mục đích này:

def __redirect(request, viewname, *args, **kwargs): 
    to = viewname 

    if callable(to): 
     to = viewname.__module__ + '.' + viewname.__name__ 
    if request.resolver_match.namespace: 
     to = '%s:%s' % (request.resolver_match.namespace, to) 

    return redirect(
     to, 
     *args, 
     **kwargs 
    ) 

Tôi đang sử dụng redirect tại đây nhưng tất cả các đối số được chuyển đến reverse, vì vậy, nó giống nhau.

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