[django] Ne récupérer qu'une partie des modèles joints.

a marqué ce sujet comme résolu.

Bonjour,
J’ai une BDD avec la structure (pour ce qui est des jointures) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
User:
  id

Categorie
  id

Article:
  id
  author: ForeignKey(User)
  categorie: ForeignKey(Categorie)

J’aimerais afficher les différents articles écrits par un utilisateur triés par catégorie comme ci dessous :

  • User:
    • Catégorie 1:
      • Article 1
      • Article 2
    • Catégorie 2:
      • Article 4
      • Article 5

Comment est-ce que je peux rédiger ma requête (Avec les QuerySet, j’ai cherché dans la doc, mais je n’arrive pas à trouver ce que je cherche) pour n’avoir que les articles de cet auteur quand j’itère sur les articles d’une catégorie ?

+0 -0

Salut !

Tu as deux moyens d’y parvenir.

Le premier est d’utiliser la relation créée par la clé étrangère dans le modèle d’utilisateur. Le nom de cette relation est défini par le paramètre related_name passé à models.ForeignKey(). Ainsi, dans tes modèles, si tu définis author = models.ForeignKey(User, related_name="articles"), tu peux récupérer les articles d’un utilisateur en faisant articles = user.articles.all().

Le second consiste à chercher parmi la liste complète des articles ceux qui ont pour auteur l’utilisateur en question. Si tu as une instance User dans la variable user, tu peux récupérer ses articles en faisant articles = Articles.objects.filter(author=user). Si tu n’as qu’un nom d’utilisateur, tu peux utiliser la magie des filtres comme ceci : articles = Articles.objects.filter(author__username=username).

Voilà, n’hésite pas à me dire si je ne suis pas clair ou que j’ai été trop vite. :)

+0 -0

Tu as été un peu vite. Déjà, dans tes propositions, tu ne parle pas des catégories. Ensuite, au final, j’aimerais afficher le tout en faisant : (à peu près)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<h1>{{ user.username }}</h1>
<ul>
    {% for categorie in categories %}
        <li>
            {{ categorie.name }}
            <ul>
                {% for article in categorie.articles %}
                    <li>{{ article.name }}</li>
                {% endfor %}
            </ul>
        </li>
    {% endfor %}
</ul>

De façon à n’avoir qu’une seule fois chaque catégorie de citée.

+0 -0

Oh, en effet, désolé.

Une solution "full-template" serait de vérifier pour chaque article si son auteur est bien celui voulu.

1
2
3
4
5
{% for article in categorie.articles %}
    {% if article.author is user %}
        <li>{{ article.name }}</li>
    {% else %}
{% endfor %}

Sinon, pour ne pas avoir de catégories vides, il est possible de le faire en Python, par exemple comme ceci.

1
2
3
4
5
user_articles = []
for category in Category.objects.all():
    user_category_articles = category.articles.filter(author=user)
    if user_category_articles:
        user_articles.append((category, user_category_articles))

De cette manière, tu récupère une liste de tuples qui contiennent en premier élément la catégorie, et en deuxième une liste des articles de l’utilisateur postés dans la-dite catégorie. Tu peux alors itérer dessus simplement.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<h1>{{ user.username }}</h1>
<ul>
    {% for group in article_groups %}  {# Each "group" is a tuple of (Category, list[Articles]). #}
        <li>
            {{ group.0.name }}
            <ul>
                {% for article in group.1 %}
                    <li>{{ article.name }}</li>
                {% endfor %}
            </ul>
        </li>
    {% endfor %}
</ul>
+0 -0

Attention avec les requêtes dans les boucles ! ;)

victor

Je ferais attention à demander les jointures lors de la première requête.

Ça se fait avec un categories.select_related('articles') non ?

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte