2010-09-11 1 views
2

Я пишу приложение в Django, которое использует [year]/[month]/[title-text] в URL-адресе для идентификации новостей. Для управления элементами я определил несколько URL-адресов, каждый из которых начинается с вышеуказанного префикса.Как написать фильтр запроса/препроцессор в Django

urlpatterns = patterns('msite.views', 
    (r'^(?P<year>[\d]{4})/(?P<month>[\d]{1,2})/(?P<slug>[\w]+)/edit/$', 'edit'), 
    (r'^(?P<year>[\d]{4})/(?P<month>[\d]{1,2})/(?P<slug>[\w]+)/$', 'show'), 
    (r'^(?P<year>[\d]{4})/(?P<month>[\d]{1,2})/(?P<slug>[\w]+)/save$', 'save'), 
) 

мне было интересно, если есть механизм в Django, который позволяет мне предобработку данного запроса взглядам edit, show и save. Он может анализировать параметры, например. year=2010, month=11, slug='this-is-a-title' и извлечь из них объект модели.

Выгода бы, что я мог бы определить свою точку зрения, как

def show(news_item): 
    '''does some stuff with the news item, doesn't have to care 
     about how to extract the item from request data''' 
    ... 

вместо

def show(year, month, slug): 
    '''extract the model instance manually inside this method''' 
    ... 

Что такое Джанго способ решения этого? Или в более общем виде существует ли механизм для реализации фильтров запросов/препроцессоров, таких как JavaEE и Ruby on Rails?

ответ

2

Возможно, вам нужны date based generic views и create/update/delete generic views?

+0

У меня есть еще много читать, пока я не получу это полностью. Фильтр, похоже, не такой тривиальный в джанго. – nre

+0

Фильтр для фильтрации объектов, как в Model.objects.filter()? –

+0

Довольно уверен, что он говорит о методе, который фильтрует (предварительно обрабатывает) запрос до его отправки фактическому обработчику запросов. Синонимичным в Java/Spring будет Interceptor ... в Rails это будет before_filter. – threejeez

1

Один из способов сделать это - написать собственный декоратор. Я тестировал это в одном из моих проектов, и это сработало.

Во-первых, пользовательский декоратор. Это нужно будет принять другие аргументы рядом с функцией, поэтому мы объявляем еще одним дизайнером, чтобы сделать это так.

decorator_with_arguments = lambda decorator: lambda * args, **kwargs: lambda func: decorator(func, *args, **kwargs) 

Теперь фактический декоратор:

@decorator_with_arguments 
def parse_args_and_create_instance(function, klass, attr_names): 
    def _function(request, *args, **kwargs): 
     model_attributes_and_values = dict() 
     for name in attr_names: 
      value = kwargs.get(name, None) 
      if value: model_attributes_and_values[name] = value 

     model_instance = klass.objects.get(**model_attributes_and_values) 
     return function(model_instance) 
    return _function 

Этот декоратор ожидает, что два дополнительных аргумента, кроме функции она декорирования. Это соответственно модельный класс, для которого экземпляр должен быть подготовлен и инъецирован, а также имена атрибутов, которые будут использоваться для подготовки экземпляра. В этом случае декоратор использует атрибуты для get экземпляра из базы данных.

И теперь «общий» вид с использованием функции show.

def show(model_instance): 
    return HttpResponse(model_instance.some_attribute) 

show_order = parse_args_and_create_instance(Order, ['order_id'])(show) 

И еще:

show_customer = parse_args_and_create_instance(Customer, ['id'])(show) 

Для того, чтобы это работало параметры конфигурации URL должны содержать одни и те же ключевые слова, как атрибуты. Конечно, вы можете настроить это, изменив декоратор.

# urls.py 
... 
url(r'^order/(?P<order_id>\d+)/$', 'show_order', {}, name = 'show_order'), 
url(r'^customer/(?P<id>\d+)/$', 'show_customer', {}, name = 'show_customer'), 
... 

Update

Как правильно @rebus pointed out вам также необходимо исследовать общие взгляды Джанго.

+0

+1 приятный зверь :) –

0

Django является питон в конце концов, так что вы можете легко сделать это:

def get_item(*args, **kwargs): 
    year = kwargs['year'] 
    month = kwargs['month'] 
    slug = kwargs['slug'] 
    # return item based on year, month, slug... 

def show(request, *args, **kwargs): 
    item = get_item(request, *args, **kwargs) 
    # rest of your logic using item 
    # return HttpResponse...