Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <!doctype html>
  2. <html lang=fr>
  3. <head>
  4. <!-- Always define the charset before the title -->
  5. <meta charset=utf-8>
  6. <title>Ajout des flux RSS, du sitemap et des commentaires avec Django — Biologeek — David Larlet</title>
  7. <!-- Define a viewport to mobile devices to use - telling the browser to assume that the page is as wide as the device (width=device-width) and setting the initial page zoom level to be 1 (initial-scale=1.0) -->
  8. <meta name="viewport" content="width=device-width, initial-scale=1"/>
  9. <!-- Fake favicon, to avoid extra request to the server -->
  10. <link rel="icon" href="data:;base64,iVBORw0KGgo=">
  11. <link type="application/atom+xml" rel="alternate" title="Feed" href="/david/log/" />
  12. <link rel="manifest" href="/manifest.json">
  13. <link rel="stylesheet" href="/static/david/css/larlet-david-_J6Rv.css" data-instant-track />
  14. <noscript>
  15. <style type="text/css">
  16. /* Otherwise fonts are loaded by JS for faster initial rendering. See scripts at the bottom. */
  17. body {
  18. font-family: 'EquityTextB', serif;
  19. }
  20. h1, h2, h3, h4, h5, h6, time, nav a, nav a:link, nav a:visited {
  21. font-family: 'EquityCapsB', sans-serif;
  22. font-variant: normal;
  23. }
  24. </style>
  25. </noscript>
  26. <!-- Canonical URL for SEO purposes -->
  27. <link rel="canonical" href="https://larlet.fr/david/biologeek/archives/20070623-ajout-des-flux-rss-du-sitemap-et-des-commentaires-avec-django">
  28. </head>
  29. <body>
  30. <div>
  31. <header>
  32. <nav>
  33. <p>
  34. <small>
  35. Je suis <a href="/david/" title="Profil public">David Larlet</a>, <a href="/david/pro/" title="Activité professionnelle">artisan</a> du web qui vous <a href="/david/pro/accompagnement/" title="Activité d’accompagnement">accompagne</a><span class="more-infos"> dans l’acquisition de savoirs pour concevoir des <a href="/david/pro/produits-essentiels/" title="Qu’est-ce qu’un produit essentiel ?">produits essentiels</a></span>. <span class="more-more-infos">Discutons ensemble d’une <a href="/david/pro/devis/" title="En savoir plus">non-demande de devis</a>.</span> Je partage ici mes <a href="/david/blog/" title="Expériences bienveillantes">réflexions</a> et <a href="/david/correspondances/2017/" title="Lettres hebdomadaires">correspondances</a>.
  36. </small>
  37. </p>
  38. </nav>
  39. </header>
  40. <section>
  41. <h1 property="schema:name">Ajout des flux RSS, du sitemap et des commentaires avec Django</h1>
  42. <article typeof="schema:BlogPosting">
  43. <div property="schema:articleBody">
  44. <img src="/static/david/biologeek/images/logos/biologeek.png" alt="vignette" style="float:left; margin: 0.5em 1em;" property="schema:thumbnailUrl" />
  45. <p>Suite de la <a href="https://larlet.fr/david/biologeek/archives/20070224-objectifs-et-motivations-de-la-refonte-de-ce-blog/">refonte de ce blog</a> qui commence vraiment à trainer en longueur... il faut dire que ça me prend souvent plus de temps de décrire ce qui est fait que de le coder&nbsp;! Du coup c'est probablement le dernier billet à ce sujet. De toute façon c'est presque terminé, il ne me reste plus qu'à mettre quelques surprises et à adapter le thème, voire peut-être à tenter un <a href="http://forum.alsacreations.com/concours/cssr2007/">Cascading Style Summer Refresh 2007</a> mais j'en doute car je vais manquer de temps ces prochains mois.</p>
  46. <h2>Ajout des flux RSS et Atom</h2>
  47. <p>J'essaye toujours d'<strong>utiliser au maximum les fonctionnalités offertes par Django</strong> qui suit la philosophie Python «&nbsp;batteries incluses ». Dans le cas des flux je voulais quelque chose de très spécifique donc il a fallu mettre un peu les mains dans le cambouis mais c'est ce qui fait le charme d'un framework&nbsp;: <strong>on peut tout contrôler</strong>&nbsp;!</p>
  48. <p>On commence par le cahier des charges, le but était d'avoir des URL du type <strong>/abonnement/{ rss, atom }/{journal, bistrot, tag, liste de tags }/</strong> afin de laisser la possibilité d'utiliser soit RSS, soit Atom tout en ayant des URL relativement courtes et compréhensibles. Au niveau du fichier des URL on retrouve donc&nbsp;:</p>
  49. <pre>from biologeek.feeds import RSSFeed, AtomFeed
  50. urlpatterns += patterns('django.contrib.syndication.views',
  51. (r'^abonnement/(?P&lt;url&gt;.*)/$', 'feed',
  52. {'feed_dict': { 'rss': RSSFeed, 'atom': AtomFeed }}
  53. ),
  54. )</pre>
  55. <p>Les clés du dictionnaire <strong>feed_dict</strong> vont être passées en paramètre de la fonction feed pour se retrouver dans l'URL donc jusqu'ici on a <strong>/abonnement/{ rss, atom }/</strong>. C'est ensuite au niveau des classes RSSFeed et AtomFeed qu'il faut décider du contenu qui va être proposé&nbsp;:</p>
  56. <pre>from django.contrib.syndication.feeds import Feed
  57. from biologeek.journal.models import Post
  58. class RSSFeed(Feed):
  59. description = u'Dernières mises à jour du site de David Larlet : biologeek.com relatives aux %s'
  60. author_name = 'David Larlet'
  61. author_link = 'http://larlet.fr/'
  62. copyright = 'Copyright (c) 2004-2007, David Larlet, Licence Art Libre'
  63. def get_object(self, bits):
  64. if len(bits) == 1:
  65. bit = bits[0]
  66. if bit == 'journal':
  67. self.title = 'Flux RSS des billets du journal du site biologeek.com'
  68. self.link = '/journal/'
  69. self.description = self.description % u'billets du journal'
  70. return Post.published.all()[:25]
  71. [...]
  72. else:
  73. raise ObjectDoesNotExist
  74. def items(self, obj):
  75. return obj</pre>
  76. <p>Je ne mets pas tout mais vous aurez compris le principe (si non <a href="http://code.google.com/p/biologeek/">vous pouvez récupérer les sources sur le dépôt</a>). En fonction de la valeur passée en URL, un contenu approprié est proposé. C'est pas vraiment élégant et cela tient au cahier des charges un peu spécial que je m'étais fixé, sinon c'est beaucoup plus simple comme vous pouvez le voir <a href="http://www.djangoproject.com/documentation/syndication_feeds/">dans la documentation</a>.</p>
  77. <p>Lorsque l'on veut passer au flux Atom, il suffit d'hériter de la classe utilisée pour le RSS&nbsp;:</p>
  78. <pre>from django.utils.feedgenerator import Atom1Feed
  79. class AtomFeed(RSSFeed):
  80. feed_type = Atom1Feed
  81. subtitle = RSSFeed.description</pre>
  82. <h2>Ajout d'un sitemap</h2>
  83. <p><strong>Un <a href="http://www.sitemaps.org/fr/">sitemap</a> est une aide pour les moteurs de recherche</strong>. C'est un fichier xml permettant d'indiquer l'importance relative des pages du site et leur fréquence de mise à jour. Il est généralement placé sur <strong>/sitemap.xml</strong> et il est nécessaire de <a href="http://www.google.com/webmasters/sitemaps/?hl=fr">le déclarer pour qu'il soit indexé</a>. On va ici se servir du <a href="http://www.djangoproject.com/documentation/sitemaps/">module sitemap de Django</a>, on rajoute donc l'URL&nbsp;:</p>
  84. <pre>from biologeek.sitemaps import sitemaps
  85. urlpatterns += patterns('django.contrib.sitemaps.views',
  86. (r'^sitemap.xml$', 'sitemap', {'sitemaps': sitemaps})
  87. )</pre>
  88. <p>La gestion des sitemaps peut se faire de manière générique, ce qui est très pratique pour les modèles que j'ai choisi&nbsp;:</p>
  89. <pre>from django.contrib.sitemaps import GenericSitemap
  90. from biologeek.journal.models import Post
  91. sitemaps = {
  92. 'journal_bestof': GenericSitemap(
  93. {
  94. 'queryset': Post.published.filter(is_bestof=True),
  95. 'date_field': 'publication_date'
  96. },
  97. priority=0.6
  98. ),
  99. 'journal': GenericSitemap(
  100. {
  101. 'queryset': Post.published.exclude(is_bestof=False),
  102. 'date_field': 'publication_date'
  103. },
  104. priority=0.4
  105. ),
  106. [...]
  107. }</pre>
  108. <p>Par contre j'ai pas mal cherché pour arriver à rajouter les liens qui ne sont pas inhérents à des modèles comme l'accueil ou les pages d'agrégation de ressources. J'ai finalement créé une classe dédiée à ça&nbsp;:</p>
  109. <pre>from django.contrib.sitemaps import Sitemap
  110. class BaseSitemap(Sitemap):
  111. priority = 0.8
  112. def items(self):
  113. return ['/', '/journal/', '/bistrot/', '/archives/', '/abonnement/', '/contact/']
  114. def location(self, obj):
  115. return obj</pre>
  116. <p>qu'il suffit ensuite d'ajouter au dictionnaire précédent. Comme vous pouvez le remarquer, je ne spécifie pas la fréquence de mise à jour car les pages de ressources sont susceptibles d'évoluer au cours du temps grâce aux commentaires et celles d'agrégations sont mises à jour de façon non régulière compte tenu de mon rythme de publication. <strong>Dans le doute, il vaut mieux s'abstenir Google saura mieux algorithmer tout ça que vous.</strong></p>
  117. <h2>Ajout des commentaires</h2>
  118. <p>Comme je le disais plus haut j'aime bien utiliser les modules déjà inclus dans Django. Pour les commentaires, <strong>je vais peut-être faire une petite exception pour deux raisons</strong>&nbsp;:</p>
  119. <ul>
  120. <li>même s'il est très puissant (peut-être trop d'ailleurs pour mes besoins&nbsp;: karma, etc), il est <strong>très peu extensible</strong> en l'état et doit être réécrit pour ça&nbsp;;</li>
  121. <li>il utilise les <strong>anciens formulaires</strong> et je ne trouve pas intéressant de continuer à les utiliser aujourd'hui.</li>
  122. </ul>
  123. <p>Je n'ai pas encore décidé de ce que j'allais faire. Il me reste aussi à intégrer l'<a href="https://larlet.fr/david/biologeek/archives/20070104-comment-utiliser-openid-la-solution-d-identification-tant-attendue/">identification via OpenID</a> pour vous rendre la vie plus facile :-).</p>
  124. <p>Prochaine étape... euh... <strong>la mise en ligne</strong>&nbsp;! J'ai pas mal galéré pour <a href="http://www.django-fr.org/">Django-fr</a> donc ça devrait aller beaucoup plus vite.</p>
  125. </div>
  126. </article>
  127. <footer>
  128. <h6 property="schema:datePublished">— 23/06/2007</h6>
  129. </footer>
  130. </section>
  131. <section>
  132. <div>
  133. <h3>Articles peut-être en rapport</h3>
  134. <ul>
  135. <li><a href="/david/biologeek/archives/20080423-biologeek-enfin-propulse-par-django/" title="Accès à Biologeek (enfin) propulsé par Django">Biologeek (enfin) propulsé par Django</a></li>
  136. <li><a href="/david/biologeek/archives/20070523-de-dotclear-a-django-migration-des-donnees-et-redirections/" title="Accès à De Dotclear à Django : migration des données et redirections">De Dotclear à Django : migration des données et redirections</a></li>
  137. <li><a href="/david/biologeek/archives/20070424-vues-generiques-heritage-et-templatetags-developpez-rapidement-avec-django/" title="Accès à Vues génériques, héritage et templatetags : développez rapidement avec Django">Vues génériques, héritage et templatetags : développez rapidement avec Django</a></li>
  138. </ul>
  139. </div>
  140. </section>
  141. <section>
  142. <div id="comments">
  143. <h3>Commentaires</h3>
  144. <div class="comment" typeof="schema:UserComments">
  145. <p class="comment-meta">
  146. <span class="comment-author" property="schema:creator">zyegfryed</span> le <span class="comment-date" property="schema:commentTime">23/06/2007</span> :
  147. </p>
  148. <div class="comment-content" property="schema:commentText">
  149. <p>Salut,<br />
  150. Excellent article, dont la collection devrait figurer quelque part sur django-fr.org ! (Cela n'engage que moi, bien sur :))<br />
  151. Je pense avoir remarqué une coquille dans le code mentionné sur l'article (je n'ai par contre pas vérifié les sources, tu me pardonneras), au niveau de la définition des éléments du sitemap :<br />
  152. <br />
  153. 'journal': GenericSitemap(<br />
  154. {<br />
  155. 'queryset': Post.published.exclude(is_bestof=False),<br />
  156. 'date_field': 'publication_date'<br />
  157. },<br />
  158. priority=0.4<br />
  159. ),<br />
  160. <br />
  161. Il me semble que la valeur de is_bestof doit être à True, puisque l'on cherche à exclure les billets BestOf qui possèdent déja leur propre référence, non ?<br />
  162. <br />
  163. Sinon, j'avais vu dans ton code source au niveau du modèle de billet (class Post il me semble) que tu utilisais un conteneur pour chaque élément formaté (Textile, Markdown, Dotclear, etc...). Ne serait il pas plus &quot;convenable&quot; de n'utiliser qu'un seul champ contenant le texte formaté, à l'aide du snippet Generic markup converter (<a href="http://www.djangosnippets.org/snippets/104/" title="http://www.djangosnippets.org/snippets/104/" rel="nofollow">www.djangosnippets.org/sn...</a>) de James Bennett (ubernostrum) ? (Modulo adaptation afin que la variable markup_func_name ne se base plus que sur une variable de configuration, mais puisse être surchargée via les paramètres kwargs par exemple ou un attribut de classe).<br />
  164. Bye :)<br />
  165. Seb</p>
  166. </div>
  167. </div>
  168. <div class="comment" typeof="schema:UserComments">
  169. <p class="comment-meta">
  170. <span class="comment-author" property="schema:creator">David, biologeek</span> le <span class="comment-date" property="schema:commentTime">23/06/2007</span> :
  171. </p>
  172. <div class="comment-content" property="schema:commentText">
  173. <p>Salut Seb,<br />
  174. <br />
  175. &gt; Excellent article, dont la collection devrait figurer quelque part sur django-fr.org !<br />
  176. <br />
  177. J'y penserais, j'attends d'avoir une catégorie Django bien définie pour poster le lien vers celle-ci.<br />
  178. <br />
  179. &gt; Il me semble que la valeur de is_bestof doit être à True, puisque l'on cherche à exclure les billets BestOf qui possèdent déja leur propre référence, non ?<br />
  180. <br />
  181. Tout à fait, en fait le billet était déjà corrigé mais le flux RSS était déjà parti un peu partout, merci de l'avoir signalé ;-).<br />
  182. <br />
  183. Concernant le snippet il était dans mes favoris mais je l'avais complètement oublié ! Je vais voir ce que je peux faire avec. Il faudra que j'intègre wiki2xhtml aussi...</p>
  184. </div>
  185. </div>
  186. <div class="comment" typeof="schema:UserComments">
  187. <p class="comment-meta">
  188. <span class="comment-author" property="schema:creator">Soso</span> le <span class="comment-date" property="schema:commentTime">25/06/2007</span> :
  189. </p>
  190. <div class="comment-content" property="schema:commentText">
  191. <p>Quand même, ça a l'air compliqué...<br />
  192. Merci en tout cas pour m'avoir &quot;tuyauté&quot; via ton exemple à l'utilité d'un sitemap pour mon blog. J'ai effectivement trouvé des générateurs de sitemap pour wordpress, je vais aller voir si ça existe pour Dotclear...<br />
  193. <br />
  194. Bon courage !</p>
  195. </div>
  196. </div>
  197. <div class="comment" typeof="schema:UserComments">
  198. <p class="comment-meta">
  199. <span class="comment-author" property="schema:creator">David, biologeek</span> le <span class="comment-date" property="schema:commentTime">25/06/2007</span> :
  200. </p>
  201. <div class="comment-content" property="schema:commentText">
  202. <p>Il y a le plugin gsitemap pour dotclear disponible ici : <a href="http://callmepep.org/bricoland/" title="http://callmepep.org/bricoland/" rel="nofollow">callmepep.org/bricoland/</a><br />
  203. <br />
  204. Merci pour les encouragements :-).</p>
  205. </div>
  206. </div>
  207. <div class="comment" typeof="schema:UserComments">
  208. <p class="comment-meta">
  209. <span class="comment-author" property="schema:creator">zyegfryed</span> le <span class="comment-date" property="schema:commentTime">25/06/2007</span> :
  210. </p>
  211. <div class="comment-content" property="schema:commentText">
  212. <p>Concernant les commentaires, James Bennett (<a href="http://www.b-list.org/" title="http://www.b-list.org/" rel="nofollow">www.b-list.org/</a>) vient de sortir une application de modération &quot;bien propre&quot; (comparée aux hacks qu'il donnait il y a un an, d'après l'auteur) : comment_utils (<a href="http://code.google.com/p/django-comment-utils/" title="http://code.google.com/p/django-comment-utils/" rel="nofollow">code.google.com/p/django-...</a>)<br />
  213. Ce pourrait être un petit plus pour la gestion des commentaires (surtout niveau modération du spam, etc.)...<br />
  214. Bye :)<br />
  215. Seb</p>
  216. </div>
  217. </div>
  218. <div class="comment" typeof="schema:UserComments">
  219. <p class="comment-meta">
  220. <span class="comment-author" property="schema:creator">David</span> le <span class="comment-date" property="schema:commentTime">27/06/2007</span> :
  221. </p>
  222. <div class="comment-content" property="schema:commentText">
  223. <p>Django-fr launched this past week. The site’s creator, David Larlet, posted the announcement to django-users: “The aim of this site is to provide translations of the documentation, useful links and of course to create a local community!” The site is still evolving as more users are becoming aware of it and contributing translations that will go through an approval process. The Django-fr group also coordinates their efforts on their Django-fr mailing list and on #django-fr on irc.freenode.net.<br />
  224. <br />
  225. <a href="http://www.djangoproject.com/weblog/2007/jun/26/djangostatusupdate/" title="http://www.djangoproject.com/weblog/2007/jun/26/djangostatusupdate/" rel="nofollow">www.djangoproject.com/web...</a><br />
  226. <br />
  227. Le début de la gloire ? ;-)<br />
  228. </p>
  229. </div>
  230. </div>
  231. <div class="comment" typeof="schema:UserComments">
  232. <p class="comment-meta">
  233. <span class="comment-author" property="schema:creator">David, biologeek</span> le <span class="comment-date" property="schema:commentTime">27/06/2007</span> :
  234. </p>
  235. <div class="comment-content" property="schema:commentText">
  236. <p>@zyegfryed : oui j'ai vu, merci pour le lien. En fait c'est en train d'être réécrit si j'en crois Jacob <a href="http://groups.google.com/group/django-developers/browse_thread/thread/f03591808a8b12f5/836e8a2b0ae37fa5#836e8a2b0ae37fa5" title="http://groups.google.com/group/django-developers/browse_thread/thread/f03591808a8b12f5/836e8a2b0ae37fa5#836e8a2b0ae37fa5" rel="nofollow">groups.google.com/group/d...</a><br />
  237. <br />
  238. Donc j'attends encore un peu mais en terme d'anti-spam c'est intéressant en effet.<br />
  239. <br />
  240. @David : la gloire, la gloire, appelons ça plutôt la reconnaissance d'une équipe motivée :-).</p>
  241. </div>
  242. </div>
  243. <div class="comment" typeof="schema:UserComments">
  244. <p class="comment-meta">
  245. <span class="comment-author" property="schema:creator">NiCoS</span> le <span class="comment-date" property="schema:commentTime">09/07/2007</span> :
  246. </p>
  247. <div class="comment-content" property="schema:commentText">
  248. <p>Merci pour cet article nickel et qui me servira un jour pour Atome :-P<br />
  249. <br />
  250. Plus je vois les contrib qui sortent pour Django, plus ça me pousse à retarder le dev d'Atome parfois :-D<br />
  251. <br />
  252. On va déjà finaliser et déployer la version 0.1 de MvMo et on verra bien ensuite dans quoi je vais me lancer (ou pas).<br />
  253. <br />
  254. ++</p>
  255. </div>
  256. </div>
  257. </div>
  258. </section>
  259. <footer>
  260. <nav>
  261. <p>
  262. <small>
  263. Je réponds quasiment toujours aux <a href="m&#x61;ilto:d&#x61;vid%40l&#x61;rlet&#46;fr" title="Envoyer un email">emails</a> (<a href="/david/signature/" title="Ma signature actuelle avec possibilité de chiffrement">signés</a>) et vous pouvez me rencontrer à Montréal. <span class="more-infos">N’hésitez pas à <a href="/david/log/" title="Être tenu informé des mises à jour">vous abonner</a> pour être tenu informé des publications récentes.</span>
  264. </small>
  265. </p>
  266. </nav>
  267. </footer>
  268. </div>
  269. <script src="/static/david/js/larlet-david-3ee43f.js" data-no-instant></script>
  270. <script data-no-instant>InstantClick.init()</script>
  271. </body>
  272. </html>