web-dev-qa-db-fra.com

Django: filtre la requête basée sur une fonction personnalisée

J'ai intégré une fonction dans ma classe de modèles Django et je veux utiliser cette fonction pour filtrer les résultats de ma requête.

  class service:
       ......
       def is_active(self):
            if datetime.now() > self.end_time:
                  return False
            return True

Maintenant, je veux utiliser cette fonction dans mon filtre de requête, quelque chose comme

nserv = service.objects.filter(is_active=True)

Je sais, pour ce cas simple 'is_active', je peux directement faire cette comparaison dans une requête de filtre, mais pour des situations plus complexes, cela peut ne pas être possible. Comment dois-je faire une requête, basée sur des fonctions personnalisées?

33
Neo

Je vous suggère d'utiliser un gestionnaire personnalisé pour votre classe, comme ceci, vous pouvez utiliser:

nserv = service.objects.are_active()

Cela serait réalisé avec quelque chose comme:

class ServiceManager(models.Manager):
    def are_active(self):
        # use your method to filter results
        return you_custom_queryset

Voir gestionnaires personnalisés

18
Lapin-Blanc

Je viens d'avoir un problème similaire. Le problème était que je devais retourner une instance de QuerySet. Une solution rapide pour moi était de faire quelque chose comme:

active_serv_ids = [service.id for service in Service.objects.all() if service.is_active()]
nserv = Service.objects.filter(id__in=active_serv_ids)

je suis sûr que ce n'est pas la manière la plus jolie et la plus performante de le faire, mais je travaille pour moi.

une façon plus détaillée de procéder serait:

active_serv_ids = []

for service in Service.objects.all():
if service.is_active():
    active_serv_ids.append(service.id)

nserv = Service.objects.filter(id__in=active_serv_ids)
16
Walter Renner

Vous ne pourrez peut-être pas le faire, mais vous pouvez post-traiter l'ensemble de requêtes avec compréhension de la liste ou expression du générateur .

Par exemple:

[x for x in Q if x.somecond()]
16

La réponse d'Ignacio est intéressante, mais elle ne renvoie pas un ensemble de requêtes. Celui-ci fait:

def users_by_role(role):
    users = User.objects.all()
    ids = [user.id for user in users if user.role == role]
    return users.filter(id__in=ids)
4
dangonfast