Nous avons maintenant toutes les fonctionnalités nécessaires pour que les créateurs publient et partagent leurs billets de blog et photos. Construisons à présent un flux plus avancé.
Le site aura deux flux :
un flux blog et photo que nous allons construire ensemble,
un flux exclusivement photo que vous allez construire vous-mĂŞme.
Si vous avez déjà travaillé avec les modèles Django, vous savez sûrement comment récupérer une instance unique d’un modèle avec  get(), et comment renvoyer des QuerySets filtrés grâce aux méthodes  filter()  et  exclude().
Examinons, en vidéo, des méthodes plus avancées de filtration et de combinaison de différents QuerySets.
Construisons la vue qui constituera notre page de flux blog et photo. Nous le ferons sur la page d’accueil existante, donc ce sera la première chose que l’on verra en se connectant.
La première tâche est de récupérer les billets de blog des créateurs auxquels l’utilisateur connecté est abonné.
Vous pouvez trouver un QuerySet des objets  User que quelqu’un suit avec  User.follows.all().
Nous voulons récupérer toutes les instances de  Blog liées à ces utilisateurs par son champ  contributors .
Pour ce faire, utilisez les recherches de champ.
Ici, nous pouvons utiliser la recherche de champin. Pour l’utiliser, vous devez spécifier le champ,contributors, suivi d’un double underscore,__ , et ensuite la recherche de champ,in. Vous l’utilisez ensuite comme argument nommé lorsque vous filtrez.
Dans ce cas, vous obtenezcontributors__in .
Voici à quoi cela ressemble dans la vue :
# blog/views.py
def home(request):
blogs = models.Blog.objects.filter(contributors__in=request.user.follows.all())
context = {
'blogs': blogs,
}
return render(request, 'blog/home.html', context=context)Et maintenant, vous voulez obtenir des photos pour le flux. Voici vos deux conditions pour filtrer le QuerySet :
Le champPhoto.uploader doit ĂŞtre un utilisateur qui est suivi.
Vous voulez exclure les photos dĂ©jĂ attachĂ©es aux instances deBlogque vous avez rĂ©cupĂ©rĂ©es.Â
Pour répondre au premier point, utilisez un filtre similaire au premier :
photos = models.Photo.objects.filter(
uploader__in=request.user.follows.all())Ensuite, excluez les photos qui sont déjà liées à des instances deBlog.
Pour les exclure, empilez la méthodeexclude sur le même QuerySet que la première.
Bien que le modèlePhoto n’ait pas d’attribut  blog, vous pouvez quand même le soumettre à des requêtes, car le modèleBlog a une relationForeignKey à Photo. Spécifiez cette relation inverse en requêtant le nom du modèle en minuscules, ce qui vous donneblog.
Pour exclure ces instances, vous pouvez utiliser :
blogs = models.Blog.objects.filter(contributors__in=request.user.follows.all())
photos = models.Photo.objects.filter(
uploader__in=request.user.follows.all()).exclude(
blog__in=blogs
)QL’attribut  starred se trouve également dans le modèleBlog. Les créateurs peuvent l’utiliser pour indiquer les posts de blog qu’ils veulent afficher sur le flux de tous les utilisateurs, que ceux-ci les suivent ou non.
Jusqu’à présent, vous n’avez étudié que les requêtes pour lesquelles les recherches peuvent être filtrées et ajoutées les unes aux autres avec « AND » (« ET »). Vous n’obtiendrez pas le résultat souhaité si vous essayez ça ici.
Vous obtiendriez ceci :
blogs = models.Blog.objects.filter(contributors__in=request.user.follows.all(), starred=True) Ça ne renvoie que les billets pour lesquels au moins l’un des  contributors est dans  user.follows et où  Blog.starredest  True.
Cependant, nous voulons renvoyer les billets si l’un des contributors est dans  user.follows ou siBlog.starred est True .
Comment nous y prendre ?
En utilisant les objets  Q  !
Vous pouvez utiliser les objets Qpour stocker certaines requĂŞtes, que vous pouvez ensuite appliquer dans les filtres. Elles peuvent ĂŞtre combinĂ©es logiquement avec les opĂ©rations AND,  & ; OR,  |  ; et  NOT ,  ~Â
Elles vous permettent de construire des requêtes de base de données complexes, au-delà de ce que  filter() et  exclude() peuvent accomplir seuls.
Pour requĂŞter les billets dont l’un des  contributors est dans  user.follows  ou dont  starredestTrue, combinez deux objetsQcontenant vos requĂŞtes avec un opĂ©rateur OR,|, comme ceci : Â
from django.db.models import Q
blogs = models.Blog.objects.filter(
Q(contributors__in=request.user.follows.all()) | Q(starred=True))Vous pouvez également nier les objets  Q en utilisant l’opérateur NOT, ~. La requête ci-dessous renverra un QuerySet identique au premier :
from django.db.models import Q
blogs = models.Blog.objects.filter(
Q(contributors__in=request.user.follows.all()) | ~Q(starred=False))Ça fonctionne, mais notre première approche a l’air plus propre.
Combinez toutes ces techniques dans la vue :
from django.db.models import Q
def home(request):
blogs = models.Blog.objects.filter(
Q(contributors__in=request.user.follows.all()) | Q(starred=True))
photos = models.Photo.objects.filter(
uploader__in=request.user.follows.all()).exclude(
blog__in=blogs
)
context = {
'blogs': blogs,
'photos': photos,
}
return render(request, 'blog/home.html', context=context) Toutes les instances  Blog et  Photo sont maintenant dans la vue. Néanmoins, si vous voulez les afficher comme un seul flux, vous allez devoir les combiner et les trier d’une façon ou d’une autre. Faisons cela maintenant !
Maintenant que nous avons récupéré les deux QuerySets pour les modèles  PhotoetBlog, nous devons les assembler dans une même liste pour les afficher sur notre flux. Voici comment en vidéo :
Si vous voulez classer un QuerySet d’un seul type de modèle, vous pouvez utiliser la méthode  order_by(), en la passant au champ que vous voulez utiliser pour organiser la séquence. Vous pouvez aussi ajouter un  – devant le champ pour inverser l’ordre des résultats.
Pour récupérer les instances deBlogen commençant par la plus récente, vous pouvez exécuter :
blogs = blogs.order_by('-date_created')Ce tri est exécuté en SQL, c’est donc plus rapide que de charger et trier des listes Python. Malheureusement, vous ne pouvez pas faire cela si vous combinez des QuerySets de différents types de modèle. Vous devez donc revenir au tri dans Python.
Vous pouvez faire différentes choses pour améliorer la performance, mais la principale sera d’utiliser itertools.chain pour assembler les QuerySets. Cette méthode retourne un itérateur qui itère sur tous les éléments itérables fournis, comme s’il s’agissait d’une seule séquence d’objets.
Vous pouvez ensuite fournir le résultat obtenu à la fonctionsorted, pour renvoyer une liste triée.
Si vous combinez ces deux éléments avec une fonctionlambdapour classer pardate_created (date de création), vous obtiendrez :
from django.db.models import Q
def home(request):
blogs = models.Blog.objects.filter(
Q(author__in=request.user.follows) | Q(starred=True))
photos = models.Photo.objects.filter(
uploader__in=request.user.follows).exclude(
blog__in=blogs
)
blogs_and_photos = sorted(
chain(blogs, photos),
key=lambda instance: instance.date_created,
reverse=True
)
context = {
'blogs_and_photos': blogs_and_photos,
}
return render(request, 'blog/home.html', context=context) Vous avez maintenant une liste des instances  Photo et  Blog  pour le flux, triée avec les instances les plus récentes en premier. Tout est prêt pour construire un flux principal combiné comprenant des billets de blog et des photos ! Ils sont même combinés en une seule liste dans le contexte à passer au gabarit.
Vous allez maintenant créer le QuerySet pour le flux exclusivement photo.
La vue est construite pour le flux principal, mais nous voulons aussi avoir un autre flux, uniquement pour les photos.
Vous allez devoir construire une vue qui servira ce flux tout photo. Elle devra :
Être appelée  photo_feed .
Récupérer un QuerySet d’instancesPhoto, pour lesquelles leuploader(la personne qui téléverse) est suivi par l’utilisateur, classées en commençant par la plus récente. Le tri doit être effectué avec l’API QuerySet.
Inclure le QuerySet dans le  context du gabarit, sous la cléphotos.
Renvoyer le rendu du gabarit  blog/photo_feed.html — pas besoin de crĂ©er ce gabarit, nous le ferons plus tard.Â
Lorsque vous serez prêt, comparez votre travail avec la solution dans le dépôt GitHub.
Vous pouvez utiliser un underscore double pour effectuer des recherches de champ sur des modèles séparés du modèle cible lorsque vous filtrez des QuerySets.
Vous pouvez utiliser des objets  Q pour construire des requêtes de base de données avancées et récupérer des objets avec la logique booléenne  AND ,  OR , et  NOT .
Vous pouvez trier les QuerySets avec la méthodeorder_by .
Vous pouvez créer un itérateur combinant les QuerySets de différents types de modèle en utilisant  itertools.chain, et en faire une liste classée avecsorted.
Le pouvoir des QuerySets va beaucoup plus loin que ces quelques exemples. Consultez la documentation Django pour encore plus de filtres utiles.Â
Maintenant que vous comprenez les fonctionnalités avancées des QuerySets, vous pouvez afficher vos posts récupérés dans le flux !