<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://flux.ducastel.name/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Jérémie Ducastel</title>
	
	<link>http://jeremie.ducastel.name</link>
	<description>développement web</description>
	<lastBuildDate>Tue, 27 Sep 2011 07:09:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://flux.ducastel.name/billets-sw" /><feedburner:info uri="billets-sw" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>billets-sw</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Traitement itératif sur un queryset</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/2tQfnvM8aq0/</link>
		<comments>http://jeremie.ducastel.name/2011/09/traitement-iteratif-sur-un-queryset/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 16:08:42 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=190</guid>
		<description><![CDATA[Si l&#8217;on a un traitement lourd à effectuer sur un QuerySet, il peut être nécessaire ou préférable de l&#8217;étaler sur plusieurs requêtes (voire de le faire exécuter en tâche de fond via une commande lancé par un cronjob). En fouillant un peu la doc, je tombe sur ceci qui permet de faire précisément ce que [...]]]></description>
			<content:encoded><![CDATA[<p>Si l&#8217;on a un traitement lourd à effectuer sur un QuerySet, il peut être nécessaire ou préférable de l&#8217;étaler sur plusieurs requêtes (voire de le faire exécuter en tâche de fond via une commande lancé par un cronjob).</p>
<p>En fouillant un peu la doc, je tombe sur ceci qui permet de faire précisément ce que je souhaitais : stocker une sérialisation de <em>la définition</em> d&#8217;un queryset, et non le queryset lui même (c&#8217;est à dire la liste des instances de modèles résultantes).</p>
<blockquote><p>If you only want to pickle the necessary information to recreate the QuerySet from the database at a later time, pickle the query attribute of the QuerySet. You can then recreate the original QuerySet (without any results loaded)
<p><a href="https://docs.djangoproject.com/en/dev/ref/models/querysets/#pickling-querysets">pickling querysets</a></p>
</blockquote>
<p>En stockant conjointement la définition de la requête et l&#8217;index auquel on est parvenu, il est alors possible d&#8217;effectuer un traitement par lots en ne chargeant à chaque itération que les données nécessaires. </p>
<p>En l&#8217;occurence un envoi de mails en série mais individualisé pour chaque destinataire à partir d&#8217;un &#8220;simple&#8221; template. Cette technique me permet de ne traiter que le résultat d&#8217;une recherche multicritères. Il faut toutefois garder en mémoire que le set de données initial peut avoir été modifié entre la sérialisation et le traitement.</p>
<p>Post-scriptum : Il m&#8217;a fallu encoder le résultat de pickle.dumps() en base 64 afin d&#8217;éviter d&#8217;obtenir une erreur <q>no module named copy_reg</q> (alors que <kbd>import copy_reg</kbd> fonctionne, étrange).</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=2tQfnvM8aq0:Ywj1VbNCDew:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=2tQfnvM8aq0:Ywj1VbNCDew:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=2tQfnvM8aq0:Ywj1VbNCDew:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=2tQfnvM8aq0:Ywj1VbNCDew:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=2tQfnvM8aq0:Ywj1VbNCDew:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/2tQfnvM8aq0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2011/09/traitement-iteratif-sur-un-queryset/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2011/09/traitement-iteratif-sur-un-queryset/</feedburner:origLink></item>
		<item>
		<title>Django : Contourner l’option auto_now et auto_now_add</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/neWQ5kqoxLc/</link>
		<comments>http://jeremie.ducastel.name/2011/07/django-contourner-loption-auto_now-et-auto_now_add/#comments</comments>
		<pubDate>Fri, 08 Jul 2011 16:27:53 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=186</guid>
		<description><![CDATA[Ces options concernent les champs DateField et DateTimeField des modèles django. Typiquement, cela permet d&#8217;obtenir des timestamps de création et de dernière modification de l&#8217;objet. Il n&#8217;est pas possible de les définir manuellement, lorsqu&#8217;un objet est créé puis enregistré en base via sa méthode save(), les champs utilisant ces options prendront pour valeur la date [...]]]></description>
			<content:encoded><![CDATA[<p>Ces options concernent les champs <a href="https://docs.djangoproject.com/en/1.3/ref/models/fields/#datefield">DateField</a> et DateTimeField des modèles django. Typiquement, cela permet d&#8217;obtenir des timestamps de création et de dernière modification de l&#8217;objet. Il n&#8217;est pas possible de les définir manuellement, lorsqu&#8217;un objet est créé puis enregistré en base via sa méthode save(), les champs utilisant ces options prendront pour valeur la date courante quelle que soit la valeur spécifiée pour l&#8217;attribut.</p>
<blockquote><p>Note that the current date is always used; it&#8217;s not just a default value that you can override.</p></blockquote>
<p>C&#8217;est parfait pour l&#8217;usage normal de ces champs, mais gênant lorsque par exemple on importe les données d&#8217;une application existante via un script dédié (voir la <a href="https://docs.djangoproject.com/en/1.3/howto/custom-management-commands/">création de commandes</a>) utilisant la couche modèle.</p>
<p>Pour contourner cet écueil, j&#8217;ai tout simplement enregistré mes objets une première fois via save(), puis une seconde fois via la méthode update de leur queryset en filtrant sur la clef primaire.</p>
<p><code class=\'prettyprint\'  >obj = MyModel()<br />
obj.save()<br />
MyModel.objects.filter(pk=obj.pk).update(created=value, updated=value)</code></p>
<p>Ce n&#8217;est certes pas très optimisé question performances, mais m&#8217;économise de créer les objets directement en SQL.</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=neWQ5kqoxLc:lKZxxX2limY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=neWQ5kqoxLc:lKZxxX2limY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=neWQ5kqoxLc:lKZxxX2limY:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=neWQ5kqoxLc:lKZxxX2limY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=neWQ5kqoxLc:lKZxxX2limY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/neWQ5kqoxLc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2011/07/django-contourner-loption-auto_now-et-auto_now_add/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2011/07/django-contourner-loption-auto_now-et-auto_now_add/</feedburner:origLink></item>
		<item>
		<title>Pépin de traduction dans les templates django</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/bN56O-ohRrY/</link>
		<comments>http://jeremie.ducastel.name/2011/06/pepin-de-traduction-dans-les-templates-django/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 08:00:37 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[i18n]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=183</guid>
		<description><![CDATA[Je viens de m&#8217;apercevoir qu&#8217;on ne pouvait pas inclure de caractères non-ascii dans les chaines marquées pour traduction au sein des templates django, du moins avec la version 1.3 du framework. C&#8217;est assez étrange dans la mesure où je pensais que django utilisait l&#8217;unicode autant que possible, et tous mes fichiers sont toujours encodés en [...]]]></description>
			<content:encoded><![CDATA[<p>Je viens de m&#8217;apercevoir qu&#8217;on ne pouvait pas inclure de caractères non-ascii dans les chaines marquées pour traduction au sein des templates django, du moins avec la version 1.3 du framework. C&#8217;est assez étrange dans la mesure où je pensais que django utilisait l&#8217;unicode autant que possible, et tous mes fichiers sont toujours encodés en UTF8, qu&#8217;il s&#8217;agisse de python ou templates HTML. Je suppose que cela part du principe que la langue de référence est généralement l&#8217;anglais. Ce n&#8217;est hélas pas toujours le cas, lorsqu&#8217;on développe une application web dont les administrateurs sont français il est tout de même plus confortable pour eux de définir le contenu en français, puis de le traduire ensuite.</p>
<p>Par défaut, la commande <kbd>manage.py makemessages</kbd> n&#8217;indique pas dans quel fichier se trouve le problème d&#8217;encodage. La solution est que j&#8217;ai trouvé est d&#8217;activer le mode verbeux avec <kb>manage.py makemessages -v 2</kbd>, chaque fichier parcouru lors de la génération du fichier .po est alors affiché à l'écran.</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=bN56O-ohRrY:34DV0X_zY1k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=bN56O-ohRrY:34DV0X_zY1k:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=bN56O-ohRrY:34DV0X_zY1k:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=bN56O-ohRrY:34DV0X_zY1k:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=bN56O-ohRrY:34DV0X_zY1k:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/bN56O-ohRrY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2011/06/pepin-de-traduction-dans-les-templates-django/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2011/06/pepin-de-traduction-dans-les-templates-django/</feedburner:origLink></item>
		<item>
		<title>Autodocumentation d’un projet ou application django</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/GoVt6Pz8MJY/</link>
		<comments>http://jeremie.ducastel.name/2011/06/autodocumentation-dun-projet-ou-application-django/#comments</comments>
		<pubDate>Wed, 01 Jun 2011 13:30:29 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[documentation]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=176</guid>
		<description><![CDATA[Je viens de découvrir et de commencer à jouer avec Sphinx, un utilitaire de génération de documentation python basé sur reStructuredText. Après m&#8217;être un peu arraché les cheveux sur l&#8217;extension autodoc censée extraire les docstrings des modules, classes etc du projet j&#8217;ai finalement trouvé ici la solution pour faire fonctionner le tout dans le cadre [...]]]></description>
			<content:encoded><![CDATA[<p>Je viens de découvrir et de commencer à jouer avec <a href="http://sphinx.pocoo.org">Sphinx</a>, un utilitaire de génération de documentation python basé sur <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>. Après m&#8217;être un peu arraché les cheveux sur l&#8217;extension <a href="http://sphinx.pocoo.org/ext/autodoc.html">autodoc</a> censée extraire les docstrings des modules, classes etc du projet j&#8217;ai finalement trouvé <a href="http://yml-blog.blogspot.com/2009/06/sphinx-autodoc-and-django-app.html">ici la solution</a> pour faire fonctionner le tout dans le cadre d&#8217;un projet django, pas nécessairement dans le <em>python path</em>; un bout de code à insérer dans le conf.py :</p>
<p><code class=\'prettyprint\'  >sys.path.insert(0, os.path.abspath('..'))</p>
<p># import de l'environnement django<br />
import settings<br />
from django.core.management import setup_environ<br />
setup_environ(settings)</code></p>
<p>(ceci suppose qu&#8217;on travaille dans le dossier docs à la racine du projet).</p>
<p>Bon ça demande un peu de travail d&#8217;écriture et de mise en forme pour être digeste, mais c&#8217;est quand même appréciable. Surtout quand on en vient (vite) à jongler avec des dizaines de fichiers ouverts de centaines de lignes chacun&#8230;</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=GoVt6Pz8MJY:YONjH9ah2Uo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=GoVt6Pz8MJY:YONjH9ah2Uo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=GoVt6Pz8MJY:YONjH9ah2Uo:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=GoVt6Pz8MJY:YONjH9ah2Uo:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=GoVt6Pz8MJY:YONjH9ah2Uo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/GoVt6Pz8MJY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2011/06/autodocumentation-dun-projet-ou-application-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2011/06/autodocumentation-dun-projet-ou-application-django/</feedburner:origLink></item>
		<item>
		<title>Garder le contrôle de ses flux déportés</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/7K_yJ6LfEIQ/</link>
		<comments>http://jeremie.ducastel.name/2009/11/garder-le-controle-de-ses-flux-deportes/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 11:27:30 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Tutoriels]]></category>
		<category><![CDATA[flux]]></category>
		<category><![CDATA[stats]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=78</guid>
		<description><![CDATA[Amis auteurs de blog, bonjour. Il y a de grande chance pour que vous ne lisiez pas ce billet sur le site où il est publié, parce que comme moi vous ne passez pas votre journée à faire le tour des centaines de blogs et sites d&#8217;information que vous suivez mais laissez la tâche à [...]]]></description>
			<content:encoded><![CDATA[<p>Amis auteurs de blog, bonjour. Il y a de grande chance pour que vous ne lisiez pas ce billet sur <a href="http://jeremie.ducastel.name">le site</a> où il est publié, parce que comme moi vous ne passez pas votre journée à faire le tour des centaines de blogs et sites d&#8217;information que vous suivez mais laissez la tâche à votre agrégateur favori. Vous n&#8217;apparaissez donc pas dans les statistiques d&#8217;accès du site, mais dans celles du flux de syndication qui est pour cela déporté vers un service externe (feedburner).</p>
<p><img src="http://jeremie.ducastel.name/wp-content/uploads/2009/11/feedburner.png" alt="feedburner" title="feedburner" width="506" height="160" class="aligncenter size-full wp-image-148" /></p>
<p>Comme vous peut être, je n&#8217;aime pas trop me rendre dépendant d&#8217;un service et risquer de perdre tous mes abonnés si l&#8217;envie me prenait de le quitter. J&#8217;ai donc configuré ces flux de telle manière que leur url reste sous le domaine du site concerné. Voici un très bref tutorial.</p>
<p><span id="more-78"></span></p>
<p>Il vous faut :</p>
<ul>
<li>Un nom de domaine dont vous pouvez éditer les DNS (Ici enregistré chez <a href="http://gandi.net">Gandi</a>).</li>
<li>Un compte google/<a href="http://feedburner.com">feedburner</a>.</li>
<li>Un outil de publication permettant de modifier l&#8217;url du flux public (ici <a href="http://wordpress.org">WordPress</a>).</li>
</ul>
<ol>
<li>
<p>Choisir le sous-domaine qui sera affecté aux flux. <q>feeds</q> par défaut pour feedburner, mais j&#8217;ai choisi <q>flux</q> pour mes sites, essentiellement francophones.</p>
</li>
<li>
<p>Générer le flux déporté par feedburner en lui fournissant l&#8217;url source du flux, c&#8217;est à dire celle produite par votre site (ici WordPress donc votreblog.com/feed ).</p>
<p><img src="http://jeremie.ducastel.name/wp-content/uploads/2009/11/burn-a-feed.jpg" alt="burn a feed" title="burn a feed" width="458" height="52" class="aligncenter size-full wp-image-138" /></p>
</li>
<li>
<p>Aller sur son <a href="http://feedburner.google.com/fb/a/mybrand">compte feedburner</a>. Copier la valeur du champ DNS CNAME (qui se termine par <q>feedproxy.ghs.google.com.</q>)</p>
</li>
<li>
<p>Ouvrir un onglet avec la configuration du domaine. Ajouter un enregistrement CNAME avec la valeur copiée précédemment. Attention, cette modification pourra prendre plusieurs heures pour être prise en compte.</p>
<p><img src="http://jeremie.ducastel.name/wp-content/uploads/2009/11/gandi-feedburner.png" alt="gandi-feedburner" title="gandi-feedburner" width="378" height="126" class="alignnone size-full wp-image-144" /></p>
</li>
<li>
<p>Revenir sur feedburner. Lui spécifier les domaines complets des flux. Activer le service.</p>
<p><img src="http://jeremie.ducastel.name/wp-content/uploads/2009/11/feedburner-domains.png" alt="feedburner-domains" title="feedburner-domains" width="363" height="61" class="alignnone size-full wp-image-143" /></p>
</li>
<li>
<p>Modifier l&#8217;adresse publique des flux sur votre site. Pour WordPress, il y a sans doute un plugin qui fait ça très bien mais pas celui que j&#8217;ai testé. Je suis donc allé dans l&#8217;editeur du thème utilisé pour modifier les <code class=\'prettyprint\' >&lt;?php bloginfo('rss2_url'); ?&gt;</code> par http://flux.votredomaine.com/slug-feedburner-du-flux. Les fichiers concernés sont généralement <q>header.php</q> (à plusieurs emplacements, dans la partie &lt;head&gt; et dans &lt;body&gt;) et <q>footer.php</q>.</p>
</li>
</ol>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=7K_yJ6LfEIQ:x4C4NoOLT4M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=7K_yJ6LfEIQ:x4C4NoOLT4M:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=7K_yJ6LfEIQ:x4C4NoOLT4M:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=7K_yJ6LfEIQ:x4C4NoOLT4M:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=7K_yJ6LfEIQ:x4C4NoOLT4M:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/7K_yJ6LfEIQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2009/11/garder-le-controle-de-ses-flux-deportes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2009/11/garder-le-controle-de-ses-flux-deportes/</feedburner:origLink></item>
		<item>
		<title>Twig, les templates Django sous PHP (le retour)</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/CTdAqW-TyhA/</link>
		<comments>http://jeremie.ducastel.name/2009/10/twig-les-templates-django-sous-php-le-retour/#comments</comments>
		<pubDate>Thu, 08 Oct 2009 15:41:31 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=100</guid>
		<description><![CDATA[Je dis le retour parce que j&#8217;avais moi-même implémenté la syntaxe de templates de Django en PHP il y a plus de deux ans (ça fait partie des librairies disponibles de webappkit). D&#8217;ailleurs, il m&#8217;avait déjà semblé voir d&#8217;autres implémentations ça et là depuis. Je ne me prononcerai pas sur twig que je ne testerai [...]]]></description>
			<content:encoded><![CDATA[<p>Je dis le retour parce que j&#8217;avais moi-même implémenté la syntaxe de templates de <a href="http://djangoproject.com/">Django</a> en PHP il y a plus de deux ans (ça fait partie des librairies disponibles de <a href="http://webappkit.net">webappkit</a>). D&#8217;ailleurs, il m&#8217;avait déjà semblé voir d&#8217;autres implémentations ça et là depuis.</p>
<p><span id="more-100"></span></p>
<p>Je ne me prononcerai pas sur <a href="http://www.twig-project.org/">twig</a> que je ne testerai sans doute pas de sitôt (vous aurez compris que le besoin est déjà couvert). Je trouve juste dommage que Django ne soit presque pas cité sur son site. D&#8217;abord c&#8217;est inélégant, mais surtout cela passe à coté de l&#8217;un des intérêts selon moi de la librairie en question : l&#8217;interopérabilité avec un framework python majeur. J&#8217;en fais actuellement l&#8217;expérience, puisque je réécris une application web PHP avec Django, et que je réutilise quasiment tel quels les templates puisque la syntaxe est la même.</p>
<p>Concernant la syntaxe en question, et l&#8217;avantage par rapport à du PHP &#8220;pur&#8221;, qui semble être le débat en cours sur twig, il y a bien sûr la possibilité d&#8217;en permettre l&#8217;édition par l&#8217;équipe éditoriale sans qu&#8217;une erreur dans le template ne mène à une erreur 500 ou une faille de sécurité. Mais aussi le système d&#8217;héritage qui permet de définir facilement un <em>layout</em> global ou par section; le marquage des contenus à traduire pour l&#8217;internationalisation, etc.</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=CTdAqW-TyhA:cw_u7YbJgHM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=CTdAqW-TyhA:cw_u7YbJgHM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=CTdAqW-TyhA:cw_u7YbJgHM:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=CTdAqW-TyhA:cw_u7YbJgHM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=CTdAqW-TyhA:cw_u7YbJgHM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/CTdAqW-TyhA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2009/10/twig-les-templates-django-sous-php-le-retour/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2009/10/twig-les-templates-django-sous-php-le-retour/</feedburner:origLink></item>
		<item>
		<title>Définir l’ip client dans les tests unitaires Django</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/bxdSVX15KRI/</link>
		<comments>http://jeremie.ducastel.name/2009/09/definir-lip-client-dans-les-tests-unitaires-django/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 15:40:06 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=98</guid>
		<description><![CDATA[Note brève, mais ça peut servir : Pour pouvoir accéder à l&#8217;ip client via request.META['REMOTE_ADDR'] lors de l&#8217;éxécution des tests unitaires, il faut la définir lors de l&#8217;instanciation du client de test. Par exemple : from django.test import TestCase from django.test.client import Client class MyTestCase(TestCase): def setUp(self): self.client = Client(REMOTE_ADDR='127.0.0.1') Sans cela vous obtiendrez une [...]]]></description>
			<content:encoded><![CDATA[<p>Note brève, mais ça peut servir :</p>
<p>Pour pouvoir accéder à l&#8217;ip client via request.META['REMOTE_ADDR'] lors de l&#8217;éxécution des tests unitaires, il faut la définir lors de l&#8217;instanciation du client de test. Par exemple :</p>
<p><code class=\'prettyprint\' >from django.test import TestCase<br />
from django.test.client import Client</p>
<p>class MyTestCase(TestCase):</p>
<p>    def setUp(self):<br />
        self.client = Client(REMOTE_ADDR='127.0.0.1')</code></p>
<p>Sans cela vous obtiendrez une exception de type KeyError parce que REMOTE_ADDR ne sera pas définie dans request.META. Ceci concerne Django 1.0.2 et j&#8217;ai trouvé la solution <a href="http://code.djangoproject.com/ticket/8551">ici</a></p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=bxdSVX15KRI:ahzo2iLqywI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=bxdSVX15KRI:ahzo2iLqywI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=bxdSVX15KRI:ahzo2iLqywI:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=bxdSVX15KRI:ahzo2iLqywI:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=bxdSVX15KRI:ahzo2iLqywI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/bxdSVX15KRI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2009/09/definir-lip-client-dans-les-tests-unitaires-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2009/09/definir-lip-client-dans-les-tests-unitaires-django/</feedburner:origLink></item>
		<item>
		<title>python : les erreurs du débutant</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/RjmlzjRP8co/</link>
		<comments>http://jeremie.ducastel.name/2009/05/python-les-erreurs-du-debutant/#comments</comments>
		<pubDate>Fri, 29 May 2009 15:38:50 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=96</guid>
		<description><![CDATA[Ou plus exactement, les erreurs du développeur habitué à un autre langage et qui doit se défaire de ses habitudes et présupposés. Trois cas concrets. Ci dessous, je veux créer une variable str, et ensuite convertir un entier en chaine. Ce qui me lève une exception. &#62;&#62;&#62; str = "un chaine" &#62;&#62;&#62; douze = str(12) [...]]]></description>
			<content:encoded><![CDATA[<p>Ou plus exactement, les erreurs du développeur habitué à un autre langage et qui doit se défaire de ses habitudes et présupposés. Trois cas concrets.</p>
<p><span id="more-96"></span></p>
<p>Ci dessous, je veux créer une <em>variable</em> <var>str</var>, et ensuite convertir un entier en chaine. Ce qui me lève une exception.</p>
<pre><code class=\'prettyprint\' >&gt;&gt;&gt; str = "un chaine"
&gt;&gt;&gt; douze = str(12)
TypeError: 'str' object is not callable</code></pre>
<p>Pourquoi ? Parce qu&#8217;en python tout est objet &#8211; y compris les fonctions, et que le concept de variable est remplacé par celui de  <q>nom</q>, qui référence les objets. En l&#8217;absence du $ qui en PHP distingue les variables des fonctions, j&#8217;avais tout simplement <q>remplacé</q> la fonction str() par une chaine.</p>
<p>Ensuite, je me suis arraché les cheveux sur une erreur de calcul incompréhensible jusqu&#8217;à ce que j&#8217;ouvre une console python pour obtenir le résultat suivant :</p>
<pre><code class=\'prettyprint\' >&gt;&gt;&gt; 9/12
0
&gt;&gt;&gt; 9.0/12.0
0.75</code></pre>
<p>Eh oui, pas de conversion automatique d&#8217;entier en float lors d&#8217;une opération. Il faut donc explicitement déclarer les opérateurs en float avec le <q>.0</q>.</p>
<p>La meilleure pour la fin. En PHP, j&#8217;avais pris pour habitude de déclarer toutes les propriétés d&#8217;instance dans le corps de la classe plutôt que dans le constructeur, afin d&#8217;y associer des <em>doc blocks </em> et d&#8217;y définir les éventuelles valeurs par défaut. Comme ceci :</p>
<pre><code class=\'prettyprint\' >&lt;?php
class MyClass {
    /**
     * @var int un entier entre un et douze
     */
    protected $qt = 3;

    public function __construct($qt=null) {
        if (is_int($qt))
          $this-&gt;qt = $qt;
    }
}</code></pre>
<p>Ce qui en python donne quelque chose comme ça :</p>
<pre><code class=\'prettyprint\' >class MyClass():
    # @var int un entier entre un et douze
    qt = 3

    def __init__(qt = None):
        if qt is not None:
            self.qt = qt</code></pre>
<p>Mais ne fonctionne pas du tout pareil. J&#8217;étais d&#8217;autant plus perdu que la classe en question était instanciée via une méthode statique et que mes instances se comportaient en <em>singleton</em> sans que ce soit le résultat souhaité. J&#8217;ai bien du perdre deux heures là dessus, à multiplier les tests unitaires et refactoriser le code pour trouver la source du problème.</p>
<pre><code class=\'prettyprint\' >&gt;&gt;&gt; first = MyClass(12)
&gt;&gt;&gt; first.qt
12
&gt;&gt;&gt; second = MyClass()
&gt;&gt;&gt; second.qt
12</code></pre>
<p>Jusqu&#8217;à ce que je réalise que tout attribut déclaré dans la classe est un attribut de celle-ci et non de l&#8217;instance, bien qu&#8217;elle soit accessible et modifiable par l&#8217;instance avec la même syntaxe (<kbd>self.qt</kbd>). Les attributs de classe sont à peu près équivalents aux propriétés statiques en php, et sont partagés entre toutes les instances de la classe.</p>
<p>Pour qu&#8217;un attribut soit propre à l&#8217;instance (local), il faut impérativement qu&#8217;il soit déclaré dans le constructeur :</p>
<pre><code class=\'prettyprint\' >class MyClass:
    def __init__(qt=None):
        if qt is not None:
            self.qt = qt
        else:
            self.qt = 3</code></pre>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=RjmlzjRP8co:CBFEohn54Oc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=RjmlzjRP8co:CBFEohn54Oc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=RjmlzjRP8co:CBFEohn54Oc:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=RjmlzjRP8co:CBFEohn54Oc:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=RjmlzjRP8co:CBFEohn54Oc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/RjmlzjRP8co" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2009/05/python-les-erreurs-du-debutant/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2009/05/python-les-erreurs-du-debutant/</feedburner:origLink></item>
		<item>
		<title>Tests de portage PHP &gt; Python</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/aIZi37P_bGA/</link>
		<comments>http://jeremie.ducastel.name/2009/05/tests-de-portage-php-python/#comments</comments>
		<pubDate>Thu, 14 May 2009 15:35:31 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=94</guid>
		<description><![CDATA[Sur un coup de tête (un peu déçu par le PHPCamp, où l&#8217;on a beaucoup parlé de technologies connexes et très peu de PHP), j&#8217;ai décidé lundi matin de tester l&#8217;implémentation en Django/Python d&#8217;une application web PHP4 que je dois réécrire pour l&#8217;internationaliser (anglais / français / chinois). Je précise que si je développe en [...]]]></description>
			<content:encoded><![CDATA[<p>Sur un coup de tête (un peu déçu par le <a href="http://barcamp.org/PhpCampParis2">PHPCamp</a>, où l&#8217;on a beaucoup parlé de technologies connexes et très peu de PHP), j&#8217;ai décidé lundi matin de tester l&#8217;implémentation en <a href="http://www.django-fr.org/">Django</a>/Python d&#8217;une application web PHP4 que je dois réécrire pour l&#8217;internationaliser (anglais / français / chinois). Je précise que si je développe en PHP depuis 2001, je parcours les manuels python depuis plusieurs années et je me suis déjà bien plongé dans la documentation de Django puisque j&#8217;ai implémenté en PHP son moteur de templates. Bien qu&#8217;ayant très peu pratiqué, je ne suis pas tout à fait novice sur ces deux technologies.</p>
<p>Voici le bilan de trois jours d&#8217;évaluation.</p>
<p><span id="more-94"></span></p>
<p><strong>Premier jour :</strong> (ré)installation de Django, la version 1.0.2, et création du projet. L&#8217;application se compose de trois interfaces : une interface web classique (qui doit donc etre multilingue), une interface <a href="http://www.xmlrpc.com/">XML-RPC</a> et  une interface client-serveur proprietaire. J&#8217;ai choisi de créer une <em>app</em> par interface. Je commence par l&#8217;interface client-serveur, qui est le point le plus critique et qui va subir prochainement une forte montée en charge. C&#8217;est elle qui va contenir la couche modèle.</p>
<p>La structure de la base de données étant déjà définie, je crée les classes modèles afin qu&#8217;elles s&#8217;adaptent aux tables existantes. Il s&#8217;agit pour l&#8217;instant de code essentiellement déclaratif. Parmi les spécificités, je créé un modèle superflu pour prendre en charge une table de liaison qui ne suit pas les conventions de nommage de Django; et un champ CSVField pour des listes de valeurs stockées en CSV dans la base. Le code ci-dessous, incluant <a href="http://www.python.org/dev/peps/pep-0257/">docstrings</a> et <a href="http://www.python.org/doc/2.5.2/lib/module-doctest.html">doctests</a> (Qui sont pour moi une forme de documentation) :</p>
<pre><code class=\'prettyprint\' >from django.db import models

class CSVField(models.Field):
    """Python list stored as a single CSV-encoded varchar field"""
    separator = ';'
    max_length = 255

    def db_type(self):
        """Define SQL column type"""
        return 'VARCHAR(%s)' % self.max_length

    def to_python(self, value):
        """Converts CSV to Python list

        &gt;&gt;&gt; CSVField.to_python('1;2;3;4;5')
        [1,2,3,4,5]"""
        return value.split(self.separator)

    def get_db_prep_value(self, value):
        """Converts Python list to CSV

        &gt;&gt;&gt; CSVField.get_db_prep_value([1,2,3,4,5])
        '1;2;3;4;5'"""
        return self.separator.join(value)</code></pre>
<p>Je crée également les premières vues, qui se contentent de réafficher les paramètres passées dans l&#8217;url.</p>
<p><strong>Deuxième jour :</strong> Je mets en place les premiers tests unitaires. Je découvre le <a href="http://docs.djangoproject.com/en/dev/topics/testing/#module-django.test.client">client de test</a> de Django, qui me permet de tester les premières vues, avec des données générées dans une base de tests en partie par un fichier yaml (<a href="http://docs.djangoproject.com/en/dev/topics/testing/#fixture-loading">fixtures</a>) et en partie via l&#8217;API de la couche  modèle dans le setUp() de la classe de tests.</p>
<p>Ensuite, je m&#8217;attaque à l&#8217;interface web classique qui doit être internationalisée. J&#8217;installe pour cela <a href="http://fr.wikipedia.org/wiki/Gettext">gettext</a> sur mon poste de travail (windows). Je crée la première vue (la page d&#8217;accueil) et les templates correspondant. Je marque les parties à traduire dans le code et les templates, et crée les fichiers de traduction anglais et chinois. Je les édite avec <a href="http://www.poedit.net/">poedit</a>, un logiciel spécialisé (de l&#8217;avantage d&#8217;utiliser un standard existant). Je copie-colle ce que me donne Google Translate pour le chinois parce que, euh, je ne parle pas cette langue. Mais je peux voir avec satisfaction les premiers idéogrammes apparaitre sur le site.</p>
<p>Ici les contenus textuels n&#8217;auront pas à être édités fréquemment. Dans le cas contraire je vois mal comment interfacer simplement gettext avec un CMS. Ici, le choix de gettext et poedit permet de faire saisir les traductions par quelqu&#8217;un qui n&#8217;est pas webmestre. De plus, gettext est également disponible en PHP via une extension spécifique.</p>
<p><strong>Troisième jour :</strong> Il est temps de passer à l&#8217;interface xml-rpc. Après une brève recherche, je tombe sur <a href="http://code.google.com/p/django-xmlrpc/">django_xmlrpc</a> qui permet d&#8217;associer les vues aux methodes fournies par le serveur (Django sert les vues selon des expressions régulières sur l&#8217;url de la requete, or avec xml-rpc toutes les méthodes sont servies sur la même url).</p>
<p>Après avoir listé les méthodes et les vues, je crée quelques tests unitaires pour la première. pour cela, je surcharge la classe TestCase de Django avec quelques méthodes utilisant les utilitaires xml-rpc de python (Voir le code ci-dessous). Après quelques tatonnements, mes premiers tests passent !</p>
<pre><code class=\'prettyprint\' >from django.test import TestCase

class XmlRpcTestCase(TestCase):
    """Specialisation de TestCase pour xml-rpc"""

    # @param string method
    # @param tuple params
    # @param string uri
    # @return Response
    def methodCall(self, method, params=(), uri='/rpc/'):
        """Issue a methodCall and sends a django's test client Response"""
        from xmlrpclib import dumps
        call = dumps(params, method)
        return self.client.post(uri, call, content_type='text/xml')

    # @param Response response
    # @param bool use_datetime if True return datetimes as object
    # @return tuple
    def parseResponse(self, response, use_datetime=True):
        """Parse django's client http Response to python tuple"""
        from xmlrpclib import loads, Fault
        try:
            result = loads(response.content, use_datetime)
            # result is a tuple params, method
            return result[0]
        except Fault, f:
            self.fail("Response was a Fault")
            return ()

    # @param string method
    # @param tuple params
    # @param string uri
    # @return tuple
    def parseCall(self, method, params=(), uri='/rpc/'):
        """method's result &lt;params&gt; as a python tuple

        assert False on method Fault"""
        response = self.methodCall(method, params, uri)
        return self.parseResponse(response)

    def assertNotFault(self, response):
        return self.assertNotContains(response, '&lt;fault&gt;')</code></pre>
<p>Comme il me reste un peu de temps, je reviens sur l&#8217;interface client-serveur qui sert un XML maison. Je découvre donc l&#8217;implémentation DOM de python pour le générer. Je rajoute quelques tests, et quitte la boite (tôt) sur un premier test positif <img src='http://jeremie.ducastel.name/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Bilan :</strong> Compte tenu de la vitesse à laquelle je me retrouve avec un prototype, et du fait que je n&#8217;ai rencontré aucun obstacle, je vais très probablement continuer l&#8217;implémentation en python et django. Il s&#8217;agit d&#8217;un choix tout à fait subjectif. J&#8217;apprécie beaucoup la syntaxe Python, son modèle tout-objet, et la philosophie <em>batteries included</em> (il y a en standard une bonne librairie pour la plupart des besoins). Et surtout, la qualité et l&#8217;exhaustivité de la documentation du langage et du framework, qui permettent de trouver très rapidement ce que l&#8217;on cherche, et même plus !</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=aIZi37P_bGA:D3pkY_zO3cw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=aIZi37P_bGA:D3pkY_zO3cw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=aIZi37P_bGA:D3pkY_zO3cw:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=aIZi37P_bGA:D3pkY_zO3cw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=aIZi37P_bGA:D3pkY_zO3cw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/aIZi37P_bGA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2009/05/tests-de-portage-php-python/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2009/05/tests-de-portage-php-python/</feedburner:origLink></item>
		<item>
		<title>Webappkit 0.13</title>
		<link>http://flux.ducastel.name/~r/billets-sw/~3/9ucenEhdKN4/</link>
		<comments>http://jeremie.ducastel.name/2009/05/webappkit-0-13/#comments</comments>
		<pubDate>Wed, 06 May 2009 15:32:14 +0000</pubDate>
		<dc:creator>Jérémie Ducastel</dc:creator>
				<category><![CDATA[Projets]]></category>
		<category><![CDATA[webappkit]]></category>

		<guid isPermaLink="false">http://jeremie.ducastel.name/?p=90</guid>
		<description><![CDATA[&#8230; est disponible au téléchargement. Pas mal de changements depuis la dernière version, puisqu&#8217;il s&#8217;est écoulé plus d&#8217;un an ! Parmi les changements, un nouveau look pour l&#8217;interface d&#8217;administration mais c&#8217;est la partie émergée de l&#8217;iceberg. Formulaire d&#8217;installation de l&#8217;administration (création d&#8217;utilisateur pour l&#8217;authentification HTTP). Génération de la structure de base des paquets depuis l&#8217;admin, [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230; est <a href="http://code.google.com/p/webappkit/downloads/detail?name=webappkit.0.13.zip">disponible au téléchargement</a>. Pas mal de changements depuis la dernière version, puisqu&#8217;il s&#8217;est écoulé plus d&#8217;un an ! Parmi les changements, un nouveau look pour l&#8217;interface d&#8217;administration mais c&#8217;est la partie émergée de l&#8217;iceberg.</p>
<p><span id="more-90"></span></p>
<ul>
<li>Formulaire d&#8217;installation de l&#8217;administration (création d&#8217;utilisateur pour l&#8217;authentification HTTP).</li>
<li>Génération de la structure de base des paquets depuis l&#8217;admin, ainsi que l&#8217;import de fichier de librairie.</li>
<li>Simplification de l&#8217;usage des tests unitaires : il suffit de déposer les classes de tests et scripts SQL de mise en place dans le dossier <q>tests/</q> du kit.</li>
<li>De nouvelles librairies intégrées (bases de données, système de fichiers, et un début d&#8217;implémentation de <a href="http://docs.djangoproject.com/en/dev/topics/forms/">Django Forms</a>.</li>
<li>Et bien sûr pas mal de polissage et de corrections de bugs.</li>
</ul>
<p><a href="http://webappkit.net"><img src="http://blog.sorcellerieweb.net/wp-content/uploads/2009/05/webappkitnet2009-05-06-180x120.png" alt="webappkit.net" title="webappkit.net" width="180" height="120" class="alignleft size-thumbnail wp-image-177" /></a></p>
<p>Le <a href="http://webappkit.net">site web</a> a également été mis à jour pour l&#8217;occasion, avec un nouveau tutorial qui se place dans le cadre de la refactorisation d&#8217;un site. La première partie est publiée, le reste suivra prochainement.</p>
<blockquote>
<p>Prenons le cas d&#8217;une application web vieillissante que nous souhaitons étendre et refactoriser. Comme par exemple, un intranet en code spaghetti, consistant en un ensemble de scripts mixant HTML, PHP et SQL. Bien sûr, il s&#8217;agit d&#8217;un exemple purement théorique. Toute coïncidence avec une application existante ne serait que pur incident statistique <img src='http://jeremie.ducastel.name/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p><a href="http://webappkit.net/tutorial">lire la suite</a></p>
</blockquote>
<p>Pour rester informés, vous pouvez suivre le <a href="http://twitter.com/webappkit">twitter du proje</a>t. Ses messages sont repris sur le site web et sur l&#8217;interface d&#8217;administration. Pour participer, vous pouvez également passer par le <a href="http://groups.google.com/group/webappkit">forum / newsgroup</a> ou <a href="mailto:contact[enlevez-ceci]@webappkit.net">envoyer un email</a>.</p>
<div class="feedflare">
<a href="http://flux.ducastel.name/~ff/billets-sw?a=9ucenEhdKN4:qbMu6_EeDiw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=9ucenEhdKN4:qbMu6_EeDiw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/billets-sw?i=9ucenEhdKN4:qbMu6_EeDiw:D7DqB2pKExk" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=9ucenEhdKN4:qbMu6_EeDiw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://flux.ducastel.name/~ff/billets-sw?a=9ucenEhdKN4:qbMu6_EeDiw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/billets-sw?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/billets-sw/~4/9ucenEhdKN4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jeremie.ducastel.name/2009/05/webappkit-0-13/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://jeremie.ducastel.name/2009/05/webappkit-0-13/</feedburner:origLink></item>
	</channel>
</rss>

