92 votes

Comment puis-je filtrer les requêtes dans les modèles Django

Je dois effectuer une requête filtrée à partir d'un modèle Django pour obtenir un ensemble d'objets équivalents au code python dans une vue:

 queryset = Modelclass.objects.filter(somekey=foo)
 

Dans mon modèle je voudrais faire

 {% for object in data.somekey_set.FILTER %}
 

mais je n'arrive pas à trouver comment écrire FILTER.

131voto

Eli Courtwright Points 53071

Vous ne pouvez pas faire cela, qui est par conception. Le framework Django auteurs ont prévu une stricte séparation de la présentation de code à partir des données de la logique. Le filtrage des modèles de données logique, et de la sortie HTML est logique de présentation.

Donc, vous avez plusieurs options. Le plus simple est de faire le filtrage, puis transmettre le résultat à l' render_to_response. Ou vous pourriez écrire une méthode dans votre modèle de sorte que vous pouvez dire {% for object in data.filtered_set %}. Enfin, vous pouvez écrire votre propre modèle d'étiquette, bien que dans ce cas précis, je ne vous le conseille.

48voto

Toby Champion Points 1453

Je viens d'ajouter une balise de modèle supplémentaire comme ceci:

 @register.filter
def in_category(things, category):
    return things.filter(category=category)
 

Alors je peux faire:

 {% for category in categories %}
  {% for thing in things|in_category:category %}
    {{ thing }}
  {% endfor %}
{% endfor %}
 

13voto

Peter Rowell Points 12444

Je rencontre ce problème sur une base régulière et souvent utiliser la fonction "ajouter une méthode" solution. Cependant, il y a certainement des cas où "ajouter une méthode" ou "calculer dans la vue" ne fonctionnent pas ou ne fonctionnent pas bien). E. g. lorsque vous êtes à la mise en cache des fragments de modèle et le besoin de certains non-trivial DB calcul pour le produire. Vous ne voulez pas faire la DB de travail, sauf si vous en avez besoin, mais vous ne savez pas si vous devez jusqu'à ce que vous êtes profondément dans le modèle logique.

Certaines autres solutions possibles:

  1. Utiliser le {% expr <expression> <var_name> %} balise de modèle trouvé à http://www.djangosnippets.org/snippets/9/ L'expression est toute juridique expression Python avec votre modèle de Contexte comme votre portée locale.

  2. Changer votre modèle de processeur. Jinja2 (http://jinja.pocoo.org/2/) a une syntaxe qui est presque identique à la Django langage de template, mais avec plein de Python de puissance disponible. Il est également plus rapide. Vous pouvez faire cela de gros, ou vous risquez de limiter son utilisation à des modèles que vous travaillez, mais l'utilisation de Django reinhardt, la "sécurité" des modèles pour designer entretenu pages.

11voto

mrmagooey Points 1170

L'autre option est que si vous avez un filtre que vous en voulez toujours appliqué, pour ajouter un custom manager sur le modèle en question, qui s'applique toujours le filtre sur les résultats retournés.

Un bon exemple de ceci est une Event modèle, où 90% des requêtes sur le modèle que vous allez vouloir quelque chose comme Event.objects.filter(date__gte=now), c'est à dire que vous êtes normalement intéresse Events qui sont à venir. Cela ressemblerait à:

class EventManager(models.Manager):
    def get_query_set(self):
        now = datetime.now()
        return super(EventManager,self).get_query_set().filter(date__gte=now)

Et dans le modèle:

class Event(models.Model):
    ...
    objects = EventManager()

Mais encore une fois, cela s'applique de la même filtre contre toutes les requêtes par défaut fait sur l' Event modèle et donc n'est pas aussi flexible certaines des techniques décrites ci-dessus.

9voto

chrisv Points 688

Cela peut être résolu avec une étiquette d'affectation:

 from django import template

register = template.Library()

@register.assignment_tag
def query(qs, **kwargs):
    """ template tag which allows queryset filtering. Usage:
          {% query books author=author as mybooks %}
          {% for book in mybooks %}
            ...
          {% endfor %}
    """
    return qs.filter(**kwargs)
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X