Как написать фильтр запросов / препроцессор в Django - PullRequest
2 голосов
/ 11 сентября 2010

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

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?

Ответы [ 3 ]

2 голосов
/ 11 сентября 2010
1 голос
/ 11 сентября 2010

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

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

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

Обновление

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

0 голосов
/ 12 сентября 2010

В конце концов, Django - это python, так что вы можете легко сделать это:

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...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...