2010-09-11 5 views
2

J'écris une application dans Django, qui utilise [year]/[month]/[title-text] dans l'URL pour identifier les nouvelles. Pour gérer les éléments, j'ai défini un certain nombre d'URL, chacune commençant par le préfixe ci-dessus.Comment écrire une demande filtre/préprocesseur dans 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'), 
) 

Je me demandais s'il existe un mécanisme de Django, ce qui me permet de prétraiter une requête donnée aux vues edit, show et save. Il pourrait analyser les paramètres, par ex. year=2010, month=11, slug='this-is-a-title' et en extrayez un objet modèle.

L'avantage serait que je pourrais définir mon point de vue que

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

au lieu de

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

Quelle est la façon de résoudre ce Django? Ou d'une manière plus générique, existe-t-il un mécanisme pour implémenter des filtres/préprocesseurs de requêtes tels que JavaEE et Ruby on Rails?

Répondre

2
+0

J'ai encore beaucoup à lire, jusqu'à ce que je reçois ce complètement. Un filtre ne semble pas si trivial dans django. – nre

+0

Filtre pour filtrer les objets comme dans Model.objects.filter()? –

+0

Bien sûr, il parle d'une méthode qui filtre (prétraiter) une requête avant qu'elle ne soit envoyée au gestionnaire de requêtes réel. Synonyme de Java/Spring serait un Interceptor ... dans Rails ce serait before_filter. – threejeez

1

Une façon de faire est d'écrire un décorateur personnalisé. J'ai testé cela dans l'un de mes projets et cela a fonctionné.

D'abord, un décorateur personnalisé. Celui-ci devra accepter d'autres arguments à côté de la fonction, donc nous déclarons un autre décorateur pour le faire ainsi.

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

Maintenant, le décorateur actuel:

@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 

Ce décorateur attend deux arguments supplémentaires en plus de la fonction qu'il est la décoration. Ce sont respectivement la classe de modèle pour laquelle l'instance doit être préparée et injectée et les noms des attributs à utiliser pour préparer l'instance. Dans ce cas, le décorateur utilise les attributs get l'instance de la base de données.

Et maintenant, une vue "générique" utilisant une fonction show.

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

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

Et un autre:

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

Pour que cela fonctionne les paramètres de configuration d'URL doit contenir les mêmes mots clés que les attributs. Bien sûr, vous pouvez personnaliser cela en peaufinant le décorateur.

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

Mise à jour

Comme @rebus correctement pointed out vous devez également enquêter sur les vues génériques de Django.

+0

+1 belle bête :) –

0

Django est python après tout, vous pouvez le faire facilement:

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... 
Questions connexes