Question

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, j'aimerais faire

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

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

Était-ce utile?

La solution

Vous ne pouvez pas faire cela, ce qui est voulu. Les auteurs du framework Django souhaitaient une séparation stricte du code de présentation de la logique de données. Filtrer les modèles est une logique de données et générer du HTML est une logique de présentation.

Vous avez donc plusieurs options. Le plus simple consiste à effectuer le filtrage, puis à transmettre le résultat à render_to_response. Vous pouvez également écrire une méthode dans votre modèle afin de pouvoir dire {% for object in data.filtered_set %}. Enfin, vous pouvez écrire votre propre balise de modèle, bien que dans ce cas précis, je vous déconseille cela.

Autres conseils

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

@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 %}

Je rencontre régulièrement ce problème et j'utilise souvent le " ajouter une méthode " Solution. Cependant, il y a certainement des cas où & Ajouter une méthode &>; ou & "le calculer dans la vue &"; ne fonctionne pas (ou ne fonctionne pas bien). Par exemple. lorsque vous mettez en cache des fragments de modèle et que vous avez besoin de calculs DB non triviaux pour le produire. Vous ne voulez pas faire le travail de base de données sauf si vous en avez besoin, mais vous ne saurez pas si vous en avez besoin tant que vous ne serez pas plongé dans la logique du modèle.

Quelques autres solutions possibles:

  1. Utilisez l'expression {% expr < expression > comme < nom_varié > Balise de modèle%} trouvée à l'adresse http://www.djangosnippets.org/snippets/9/ . L'expression est une expression légale Python avec le contexte de votre modèle comme portée locale.

  2. Modifiez votre processeur de modèle. Jinja2 ( http://jinja.pocoo.org/2/ ) a une syntaxe presque identique à le langage de template Django, mais avec toute la puissance Python disponible. C'est aussi plus rapide. Vous pouvez le faire en gros ou limiter son utilisation aux modèles sur lesquels vous travaillez, mais utilisez le & "Plus sûr &" De Django. modèles pour les pages gérées par le concepteur.

Cela peut être résolu avec une balise d'attribution:

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)

L’autre option consiste à ajouter un gestionnaire personnalisé sur le modèle en question qui applique toujours le filtre aux résultats renvoyés.

Un bon exemple de ceci est un modèle Event dans lequel vous voulez quelque chose comme Event.objects.filter(date__gte=now) pour 90% des requêtes que vous effectuez sur le modèle, c'est-à-dire que vous êtes normalement intéressé par Events prochain. 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 applique le même filtre à toutes les requêtes par défaut effectuées sur le modèle <=> et rend donc moins flexible certaines des techniques décrites ci-dessus.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top