<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	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/"
	>

<channel>
	<title>Blog technique sur les technologies web &#187; Web</title>
	<atom:link href="https://blog.developpez.com/laurent-luce/pcategory/web/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/laurent-luce</link>
	<description></description>
	<lastBuildDate>Fri, 08 Oct 2010 19:33:04 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Amazon S3 upload et download avec Python/Django</title>
		<link>https://blog.developpez.com/laurent-luce/p9364/web/amazon_s3_upload_et_download_avec_python</link>
		<comments>https://blog.developpez.com/laurent-luce/p9364/web/amazon_s3_upload_et_download_avec_python#comments</comments>
		<pubDate>Fri, 08 Oct 2010 19:31:20 +0000</pubDate>
		<dc:creator><![CDATA[laurent luce]]></dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article explique comment uploader des fichiers vers Amazon S3 en utilisant Python/Django et comme downloader des fichiers à partir de S3 vers votre PC. On démarre avec un fichier dans /var/www/data posté par un utilisateur via un formulaire. Sur Gourmious, j&#8217;ai besoin d&#8217;utiliser plusieurs versions de la même photo: petite taille, version pour téléphones portables etc&#8230; Pour celà, je génère 4 photos de taille différente avec un script bash à partir de mon appli [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Cet article explique comment uploader des fichiers vers Amazon S3 en utilisant Python/Django et comme downloader des fichiers à partir de S3 vers votre PC.<br />
<span id="more-5"></span><br />
<br />
On démarre avec un fichier dans /var/www/data posté par un utilisateur via un formulaire.<br />
<br />
Sur <a href="http://www.gourmious.com">Gourmious</a>, j&rsquo;ai besoin d&rsquo;utiliser plusieurs versions de la même photo: petite taille, version pour téléphones portables etc&#8230; Pour celà, je génère 4 photos de taille différente avec un script bash à partir de mon appli Django quand je reçois la photo. Je passe l&rsquo;identifiant de la photo comme paramètre: &lsquo;id&rsquo;.</p>
<pre>
p = subprocess.Popen(["/bin/bash", "/usr/bin/resize.x", id], stdout = subprocess.PIPE)
p.stdout.read()
</pre>
<p>resize.x contient le code suivant:</p>
<pre>
#!/bin/bash
filename=$1
convert -resize "500x500" /var/www/data/$filename.png /var/www/data/$filename"_s.png"
convert -resize "300x300" /var/www/data/$filename.png /var/www/data/$filename"_m.png"
convert -resize "75x75" /var/www/data/$filename.png /var/www/data/$filename"_t.png"
convert -resize "48x48" /var/www/data/$filename.png /var/www/data/$filename"_e.png"
</pre>
<p>On a donc nos 5 fichiers (originale + 4 versions de taille différente) à uploader vers Amazon S3.<br />
<br />
On a besoin de créer un bucket qui va contenir nos fichiers. Celà peut-être fait à partir de la console de configuration sur Amazon.<br />
<br />
Pour la suite, on va utiliser la librairie python <a href="http://boto.s3.amazonaws.com/index.html">boto</a> qui va nous faciliter la tâche.<br />
<br />
On a besoin de définir les variables suivantes dans settings.py dans notre projet Django.</p>
<pre>
BUCKET_NAME = 'bucket_name'
AWS_ACCESS_KEY_ID = ...
AWS_SECRET_ACCESS_KEY = ...
</pre>
<h2>Upload vers S3</h2>
<p>Voici le code pour uploader nos photos (plus les versions de taille différente):</p>
<pre>
def push_picture_to_s3(id):
  try:
    import boto
    from boto.s3.key import Key
    # demande à boto de n'imprimer que les messages critical
    logging.getLogger('boto').setLevel(logging.CRITICAL)
    bucket_name = settings.BUCKET_NAME
    # on se connecte au bucket
    conn = boto.connect_s3(settings.AWS_ACCESS_KEY_ID,
                    settings.AWS_SECRET_ACCESS_KEY)
    bucket = conn.get_bucket(bucket_name)
    # on s'occupe des 5 fichiers: original + 4 versions de taille différente
    suffixes = ['', '_e', '_m', '_s', '_t']
    for s in suffixes:
      key = 'dish_%s%s.png' % (id, s)
      fn = '/var/www/data/%s%s%s' % (id, s, ext)
      # on crée une clé pour ce fichier
      k = Key(bucket)
      k.key = key
      k.set_contents_from_filename(fn)
      # on indique ce fichier comme étant public pour pouvoir y accéder
      # en utilisant un lien comme http://s3.amazonaws.com/bucket_name/key
      k.make_public()
      # on efface le fichier localement
      os.remove(fn)
  except:
    ...
</pre>
<h2>Download à partir de S3</h2>
<p>Comme on l&rsquo;a vu, on peut accéder au fichier sur Amazon S3 en utilisant le lien: http://s3.amazonaws.com/bucket_name/key. On peut également y accéder en utilisant la librairie boto pour downloader les fichiers. J&rsquo;utilise cette méthode pour créer une copie journalière sur mon PC.<br />
<br />
Voici le script Python pour faire cela:</p>
<pre>
import boto
import sys, os
from boto.s3.key import Key

LOCAL_PATH = '/backup/s3/'
AWS_ACCESS_KEY_ID = '...'
AWS_SECRET_ACCESS_KEY = '...'

bucket_name = 'bucket_name'
# on se connecte au bucket
conn = boto.connect_s3(AWS_ACCESS_KEY_ID,
                AWS_SECRET_ACCESS_KEY)
bucket = conn.get_bucket(bucket_name)
# on parcoure la liste des fichiers
bucket_list = bucket.list()
for l in bucket_list:
  keyString = str(l.key)
  # on vérifie si le fichier existe localement, si non, on le télécharge
  if not os.path.exists(LOCAL_PATH+keyString):
    l.get_contents_to_filename(LOCAL_PATH+keyString)
</pre>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Upload vers Django avec barre de progression en utilisant Ajax et jQuery</title>
		<link>https://blog.developpez.com/laurent-luce/p9342/web/upload_vers_django_avec_barre_de_progres</link>
		<comments>https://blog.developpez.com/laurent-luce/p9342/web/upload_vers_django_avec_barre_de_progres#comments</comments>
		<pubDate>Sun, 03 Oct 2010 04:54:10 +0000</pubDate>
		<dc:creator><![CDATA[laurent luce]]></dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article décrit comment j&#8217;ai mis en place l&#8217;upload de fichiers vers un serveur Django + une barre de progression avec Ajax et jQuery. J&#8217;avais besoin de cette fonctionnalité pour que les utilisateurs de Gourmious puissent poster leurs photos de plats. Côté client On a besoin d&#8217;un formulaire pour que l&#8217;utilisateur puisse uploader un fichier. &#60;form id=&#34;form_upload&#34; action=&#34;/upload&#34; method=&#34;POST&#34;&#62; &#160; &#60;input type=&#34;file&#34; name=&#34;picture&#34; id=&#34;picture&#34; /&#62; &#160; &#60;input type=&#34;hidden&#34; id=&#34;X-Progress-ID&#34; name=&#34;X-Progress-ID&#34; value=&#34;&#34;/&#62; &#160; &#60;input type=&#34;hidden&#34; id=&#34;id&#34; [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Cet article décrit comment j&rsquo;ai mis en place l&rsquo;upload de fichiers vers un serveur Django + une barre de progression avec Ajax et jQuery. J&rsquo;avais besoin de cette fonctionnalité pour que les utilisateurs de <a href="http://www.gourmious.com">Gourmious</a> puissent poster leurs photos de plats.<br />
<span id="more-4"></span></p>
<h2>Côté client</h2>
<p>On a besoin d&rsquo;un formulaire pour que l&rsquo;utilisateur puisse uploader un fichier.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;form id=&quot;form_upload&quot; action=&quot;/upload&quot; method=&quot;POST&quot;&gt; <br />
&nbsp; &lt;input type=&quot;file&quot; name=&quot;picture&quot; id=&quot;picture&quot; /&gt; <br />
&nbsp; &lt;input type=&quot;hidden&quot; id=&quot;X-Progress-ID&quot; name=&quot;X-Progress-ID&quot; value=&quot;&quot;/&gt; <br />
&nbsp; &lt;input type=&quot;hidden&quot; id=&quot;id&quot; name=&quot;id&quot; value=&quot;&quot;/&gt; <br />
&nbsp; &lt;input id=&quot;form_submit_button&quot; class=&quot;tp-button&quot; type=&quot;submit&quot; value=&quot;Submit&quot; /&gt; <br />
&nbsp; &lt;/form&gt;</div></div>
<p>Nous avons ajouté 2 inputs, la première &lsquo;X-Progress-ID&rsquo; est l&rsquo;identifiant de l&rsquo;upload pour que l&rsquo;on puisse supporter plusieurs uploads simultanément.<br />
<br />
On a l&rsquo;input &lsquo;id&rsquo; qui représente l&rsquo;identifiant du plat dans notre cas.<br />
<br />
On va utiliser Ajax pour la requête POST pour pouvoir l&rsquo;intégrer dans une interface web moderne avec une barre de progression. Pour cela, on va utiliser le <a href="http://jquery.malsup.com/form/#download">plugin jQuery Form</a>.<br />
<br />
La méthode ajaxSubmit() va s&rsquo;occuper de tout pour nous <img src="https://blog.developpez.com/laurent-luce/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /><br />
<br />
On génère une string aléatoire pour l&rsquo;ID de l&rsquo;upload et on l&rsquo;attribue à l&rsquo;input &lsquo;X-Progress-ID&rsquo;.<br />
On a besoin de spécifier l&rsquo;URL pour l&rsquo;upload et 2 functions: 1 qui est appelée avant l&rsquo;upload et une après.</p>
<pre>
$('#X-Progress-ID').val('random string');
var options = {
  dataType: 'xml',
  url: '/upload?X-Progress-ID='+$('#X-Progress-ID').val(),
  beforeSubmit: showRequest,
  success: showResponse
}
$('#form_upload').ajaxSubmit(options);
</pre>
<p>Quand l&rsquo;utilisateur clique sur le bouton pour démarrer l&rsquo;upload, on doit présenter une barre de progression. Pour cela, on utilise le code JS suivant pour ajouter une barre de progression au formulaire. La méthode progressBar() fait partie de <a href="http://t.wits.sg/jquery-progress-bar/">jQuery progress bar plugin</a>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$('#form_upload').find('#form_submit_input').append('&lt;span id=&quot;uploadprogressbar&quot;&gt;&lt;/span&lt;'); <br />
$('#form_upload').find('#uploadprogressbar').progressBar();</div></div>
<p>On a aussi besoin d&rsquo;une fonction pour récupérer la progression de l&rsquo;upload à partir du serveur pour mettre à jour la barre de progression régulierement.<br />
<br />
Pour faire cela, on utilise setInterval() afin d&rsquo;émettre une requête GET pour récupérer la valeur de la progression au format JSON. On passe l&rsquo;identifiant de l&rsquo;upload dans la requête. L&rsquo;upload est terminée quand la valeur null est renvoyée. </p>
<pre>
function startProgressBarUpdate(upload_id) {
  $("#uploadprogressbar").fadeIn();
  if(g_progress_intv != 0)
    clearInterval(g_progress_intv);
  g_progress_intv = setInterval(function() {
    $.getJSON("/web_modules/process.py?request=get_upload_progress&amp;X-Progress-ID="
+ upload_id, function(data) {
      if (data == null) {
        $("#uploadprogressbar").progressBar(100);
        clearInterval(g_progress_intv);
        g_progress_intv = 0;
        return;
      }
      var percentage = Math.floor(100 * parseInt(data.uploaded) / parseInt(data.length));
      $("#uploadprogressbar").progressBar(percentage);
    });
  }, 5000);
}
</pre>
<h2>Coté serveur</h2>
<p>On a besoin d&rsquo;une méthode dans views.py pour recevoir les fichiers. On lit chaque fichier bloc par bloc pour éviter d&rsquo;utiliser trop de RAM.</p>
<pre>
def upload(request):
  id = request.POST['id']
  path = '/var/www/pictures/%s' % id
  f = request.FILES['picture']
  destination = open(path, 'wb+')
  for chunk in f.chunks():
    destination.write(chunk)
  destination.close()
</pre>
<p>Comment le serveur suit la progression de l&rsquo;upload ? On doit utiliser un file handler spécial. On utilise <a href="http://djangosnippets.org/snippets/678/">UploadProgressCachedHandler</a>. On a juste besoin de la classe, pas la méthode pour la vue car on va s&rsquo;en occuper nous même. Vous pouvez ajouter cette classe dans un fichier s&rsquo;appelant uploadprogresscachedhandler.py dans votre projet Django.<br />
<br />
Pour activer cet handler, on ajoute les lignes suivantes dans settings.py.</p>
<pre>
from django.conf import global_settings
FILE_UPLOAD_HANDLERS = (uploadprogresscachedhandler.UploadProgressCachedHandler', ) \
+ global_settings.FILE_UPLOAD_HANDLERS
</pre>
<p>On a aussi besoin d&rsquo;activer un système de cache. On va utiliser memcached. On ajoute la ligne suivante dans settings.py.</p>
<pre>
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
</pre>
<p>Assurez vous d&rsquo;avoir memcached et les bindings python installés sur votre serveur.<br />
<br />
On a besoin d&rsquo;ajouter une méthode dans views.py pour retourner la progression de l&rsquo;upload au client quand il le demande. La valeur de la progression se trouve dans la cache spécifiée par la clé remoteaddress_uploadid<br />
</p>
<pre>
def get_upload_progress(request):
  from django.utils import simplejson
  cache_key = "%s_%s" % (request.META['REMOTE_ADDR'], request.GET['X-Progress-ID'])
  data = cache.get(cache_key)
  return HttpResponse(simplejson.dumps(data))
</pre>
<p>Voila, c&rsquo;est tout pour l&rsquo;instant. N&rsquo;hesitez pas à ajouter des commentaires pour continuer la discussion.<br />
<br />
Si vous avez aimé cet article, ça serait cool d’aller sur mon site <a href="http://www.gourmious.com">Gourmious</a> pour découvrir et partager vos plats préférés au resto.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Créer un package Debian pour une application Django</title>
		<link>https://blog.developpez.com/laurent-luce/p9327/web/creer_un_package_debian_pour_une_applica</link>
		<comments>https://blog.developpez.com/laurent-luce/p9327/web/creer_un_package_debian_pour_une_applica#comments</comments>
		<pubDate>Mon, 27 Sep 2010 18:08:37 +0000</pubDate>
		<dc:creator><![CDATA[laurent luce]]></dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Dans cet article, on va créer un package Debian pour une application Django. Le package va être responsable pour: Installer l&#8217;application Configurer le serveur web (dans notre cas: Lighttpd + fastcgi) Script init.d pour démarrer/arrêter le serveur Django On va utiliser une template debconf pour demander 1 question à l&#8217;utilisateur. Cela va rendre le package plus dynamique.. On présume que l&#8217;application Django se trouve dans /usr/share/djangoapp . C&#8217;est là où se trouve settings.py, manage.py, views.py [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Dans cet article, on va créer un package Debian pour une application Django.</p>
<p>Le package va être responsable pour:</p>
<ul>
<li>Installer l&rsquo;application</li>
<li>Configurer le serveur web (dans notre cas: Lighttpd + fastcgi)</li>
<li>Script init.d pour démarrer/arrêter le serveur Django</li>
</ul>
<p><span id="more-3"></span><br />
On va utiliser une template debconf pour demander 1 question à l&rsquo;utilisateur. Cela va rendre le package plus dynamique..</p>
<p>On présume que l&rsquo;application Django se trouve dans /usr/share/djangoapp . C&rsquo;est là où se trouve settings.py, manage.py, views.py etc&#8230;</p>
<p>Tout d&rsquo;abord, on crée un dossier debian et on copie le dossier de l&rsquo;application Django dedans.</p>
<pre>
mkdir ./debian
mkdir -p ./debian/usr/share/
cp -r /usr/share/djangoapp ./debian/usr/share/
</pre>
<p>On a également besoin de créer un dossier DEBIAN dans debian/</p>
<pre>mkdir ./debian/DEBIAN</pre>
<h2>Fichiers dans DEBIAN</h2>
<p>Ce dossier doit contenir les fichiers suivants:</p>
<ul>
<li>control</li>
<li>config</li>
<li>conffiles</li>
<li>templates</li>
<li>postinst</li>
<li>postrm</li>
<li>preinst</li>
<li>prerm</li>
</ul>
<p><strong>control</strong></p>
<p>C&rsquo;est le fichier le plus important dans un package Debian. Ce fichier défini le package et ses dépendances. Il contient dans notre cas le texte suivant:</p>
<pre>
Package: djangoapp
Version: 0.1-1
Section: devel
Priority: optional
Architecture: all
Depends: python, python-django, python-flup, debconf, lighttpd
Maintainer: Laurent Luce
Description: short description
 long description
</pre>
<p>Le paramètre &laquo;&nbsp;depends&nbsp;&raquo; est une liste de packages dont depends notre package.</p>
<p><strong>config</strong></p>
<p>config est un script demandant des questions à l&rsquo;utilisateur avant que le package soit installé. On demande une seule question dans notre exemple:</p>
<pre>
#!/bin/sh -e

# Source debconf library.
. /usr/share/debconf/confmodule

# votre nom ?
db_input critical djangoapp/username || true
db_go
</pre>
<p>On a besoin d&rsquo;inclure le module debconf. Notre question est de type &lsquo;critical&rsquo;.</p>
<p>Mais où est la définition de notre question ? Elle est défini dans le fichier templates</p>
<p><strong>templates</strong></p>
<pre>
Template: djangoapp/username
Type: string
Description: Username:
Ce package nécessite votre nom
</pre>
<p><strong>conffiles</strong><br />
Ce fichier contient les fichiers de configuration généralement localisés dans /etc . Nous ajoutons le fichier de lancement de Django.</p>
<pre>
/etc/init.d/django
</pre>
<p><strong>preinst</strong><br />
Ce script est executé avant l&rsquo;installation du package.</p>
<pre>
#!/bin/bash
set -e

# stop le serveur Django
if [ -f /etc/init.d/django ]
then
  invoke-rc.d django stop
fi
</pre>
<p><strong>postinst</strong><br />
Ce script est executé après l&rsquo;installation du package.</p>
<pre>
#!/bin/sh
set -e

# Source debconf library.
. /usr/share/debconf/confmodule

db_get djangoapp/username
username="$RET"
# utiliser le nom de l'utilisateur comme bon vous semble

# enregistrer Django
update-rc.d django defaults 90 >/dev/null
# démarrer Django
invoke-rc.d django start

db_stop
</pre>
<p><strong>postrm</strong><br />
Ce script est executé après que le package soit désinstallé.</p>
<pre>
#!/bin/bash
set -e

if [ "$1" = "purge" -a -e /usr/share/debconf/confmodule ]; then
    # Source debconf library.
    . /usr/share/debconf/confmodule
    # Supprimer mes changements dans la base de données
    db_purge
fi

if [ "$1" = "remove" ]; then

# Source debconf library.
. /usr/share/debconf/confmodule

# Supprimer le script de lancement de Django
update-rc.d -f django remove

# Supprimer mes changements dans la base de données
db_purge
fi
</pre>
<p><strong>prerm</strong><br />
Ce script est exécuté avant la désinstallation du package</p>
<pre>
#!/bin/bash
set -e

# stop django server
invoke-rc.d django stop
</pre>
<h2>Configuration du serveur web</h2>
<p>On a besoin de modifier le fichier de configuration de lighttpd: lighttpd.conf:</p>
<p>mod_fastcgi doit être ajouté à la liste des modules du serveur.</p>
<p>le serveur Django écoute sur le port 3033:</p>
<pre>
fastcgi.server = (
  "/djangoapp.fcgi" => (
    "main" => (
      # Use host / port instead of socket for TCP fastcgi
      "host" => "127.0.0.1",
      "port" => 3033,
      "check-local" => "disable",
  ))
)
</pre>
<h2>Script Django init.d</h2>
<p>C&rsquo;est le moment d&rsquo;ajouter notre script de lancement pour Django:</p>
<pre>
#! /bin/sh
### BEGIN INIT INFO
# Provides:          FastCGI servers for Django
# Required-Start:    networking
# Required-Stop:     networking
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Django FastCGI
#

DJANGO_SITE="djangoapp"
SITE_PATH=/var/www
RUNFILES_PATH=$SITES_PATH/tmp
HOST=127.0.0.1
PORT_START=3033
RUN_AS=www-data

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Django FastCGI"
NAME=$0
SCRIPTNAME=/etc/init.d/$NAME

#
#       Function that starts the daemon/service.
#
d_start()
{
    # Starting all Django FastCGI processes
    echo -n ", $DJANGO_SITE"
    if [ -f $RUNFILES_PATH/$DJANGO_SITE.pid ]; then
        echo -n " already running"
    else
       start-stop-daemon --start --quiet \
                       --pidfile $RUNFILES_PATH/$DJANGO_SITE.pid \
                       --chuid $RUN_AS --exec /usr/bin/env -- python \
                       $SITE_PATH/$DJANGO_SITE/manage.py runfcgi \
                       host=$HOST port=$PORT \
                       pidfile=$RUNFILES_PATH/$DJANGO_SITE.pid
    fi
}

#
#       Function that stops the daemon/service.
#
d_stop() {
    # Killing all Django FastCGI processes running
    echo -n ", $DJANGO_SITE"
    start-stop-daemon --stop --quiet --pidfile $RUNFILES_PATH/$SITE.pid \
                          || echo -n " not running"
    if [ -f $RUNFILES_PATH/$DJANGO_SITE.pid ]; then
        rm $RUNFILES_PATH/$DJANGO_SITE.pid
    fi
}

ACTION="$1"
case "$ACTION" in
    start)
        echo -n "Starting $DESC: $NAME"
        d_start
        echo "."
        ;;

    stop)
        echo -n "Stopping $DESC: $NAME"
        d_stop
        echo "."
        ;;

    restart|force-reload)
        echo -n "Restarting $DESC: $NAME"
        d_stop
        sleep 1
        d_start
        echo "."
        ;;

    *)
        echo "Usage: $NAME {start|stop|restart|force-reload}" >&amp;2
        exit 3
        ;;
esac

exit 0
</pre>
<p>Le script doit être placé dans ./debian/etc/init.d/</p>
<p>On a besoin de créer un lien de /var/www/djangoapp vers /usr/share/djangoapp</p>
<h2>changelog, changelog.Debian et copyright</h2>
<p>Ces fichiers sont nécessaires pour notre package:</p>
<p><strong>changelog</strong></p>
<pre>
djangoapp (0.1-1) unstable; urgency=low

  * Initial release.
    + Initial package

 -- Laurent Luce Fri, 01 Jan 2010 00:00:00 +0000
</pre>
<p>Dans notre cas, changelog.Debian contient la même chose que changelog.</p>
<p><strong>copyright</strong></p>
<pre>
DjangoApp

Copyright: bla bla

2010-01-01

The home page of xxx is at: 

http://www.xxx.com

Copyright xxx 2010
</pre>
<p>On doit placer ces fichiers proprement:</p>
<pre>
mkdir -p ./debian/usr/share/doc/djangoapp
cp changelog changelog.Debian copyright ./debian/usr/share/doc/djangoapp/
gzip --best ./debian/usr/share/doc/djangoapp/changelog
gzip --best ./debian/usr/share/doc/djangoapp/changelog.Debian
</pre>
<h2>Construction du package</h2>
<p>On doit régler les permissions:</p>
<pre>
find ./debian -type d | xargs chmod 755
</pre>
<p>On construit le package et on le vérifie de cette manière:</p>
<pre>
fakeroot dpkg-deb --build debian
mv debian.deb DjangoApp_0.1-1_all.deb
lintian DjangoApp_0.1-1_all.deb
</pre>
<p>Notre package est prêt !!!</p>
<p>Si vous avez aimé cet article, ca serait cool d&rsquo;aller sur mon site <a href="http://www.gourmious.com">Gourmious</a> pour découvrir et partager vos plats préférés au resto.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Envoyer des fichiers à partir d&#8217;un client python vers Django</title>
		<link>https://blog.developpez.com/laurent-luce/p9326/web/envoyer_des_fichiers_a_partir_d_un_clien</link>
		<comments>https://blog.developpez.com/laurent-luce/p9326/web/envoyer_des_fichiers_a_partir_d_un_clien#comments</comments>
		<pubDate>Mon, 27 Sep 2010 18:04:54 +0000</pubDate>
		<dc:creator><![CDATA[laurent luce]]></dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Dans cet article, on va uploader des fichiers à partir d&#8217;un client python vers Django, de manière efficace (streaming côté client et côté serveur). On va uploader le contenu d&#8217;un dossier + utiliser l&#8217;authentification. Côté client Un module très sympa à utiliser est poster. Ca aide à faire des requêtes POST en utilisant le codage multipart/form-data. Le module va nous permettre également de faire du streaming. Tout d&#8217;abord, on crée un cookie: cj = cookielib.CookieJar() [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Dans cet article, on va uploader des fichiers à partir d&rsquo;un client python vers Django, de manière efficace (streaming côté client et côté serveur). On va uploader le contenu d&rsquo;un dossier + utiliser l&rsquo;authentification.<br />
<span id="more-2"></span></p>
<h2>Côté client</h2>
<p>Un module très sympa à utiliser est <a href="http://atlee.ca/software/poster/">poster</a>. Ca aide à faire des requêtes POST en utilisant le codage multipart/form-data. Le module va nous permettre également de faire du streaming.</p>
<p>Tout d&rsquo;abord, on crée un cookie:</p>
<pre>
cj = cookielib.CookieJar()
</pre>
<p>Ensuite, on a besoin d&rsquo;importer quelques fonctions du module poster:</p>
<pre>
from poster.encode import multipart_encode
from poster.streaminghttp import StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandler
</pre>
<p>On crée un opener en utilisant les fonctions de streaming du module poster:</p>
<pre>
handlers = [StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandler]
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj), *handlers)
urllib2.install_opener(opener)
</pre>
<p>On pourrait utiliser la fonction register_openers() du module poster mais elle ne supporte l&rsquo;authentification donc on utilise les fonctions internes.</p>
<p>On lit la liste des fichiers du dossier &lsquo;/data&rsquo; et on les envoie au serveur.</p>
<pre>
params = {}
dir = u'/data/'
for f in os.listdir(dir):
  params[f] = open(dir+f)
data, headers = multipart_encode(params)
url = 'https://test/upload.py'
req = urllib2.Request(url, data, headers)
result = urllib2.urlopen(req)
</pre>
<h2>Côté serveur</h2>
<p>On ne veut pas saturer la mémoire vive donc on va lire les données par paquets.</p>
<p>Les fichiers reçus sont dans request.FILES qui est un dictionnaire d&rsquo;objets de type UploadedFile</p>
<p>Si la taille du fichier est supérieur à 2.5MB (cette limite peut être modifiée dans votre settings.py), il sera divisé en plusieurs paquets pour ne pas utiliser trop de RAM.</p>
<p>On ajoute le code suivant dans views.py pour recevoir les fichiers.</p>
<pre>
for key, file in request.FILES.items():
  path = '/data/'+ file.name
  dest = open(path.encode('utf-8'), 'wb+')
  if file.multiple_chunks:
    for c in file.chunks():
      dest.write(c)
    else:
      dest.write(file.read())
    dest.close()
</pre>
<p>Voila, tous les fichiers envoyés sont maintenant sur le serveur et cela d&rsquo;une manière optimisée.</p>
<p>N&rsquo;hésitez pas à commenter cet article.</p>
<p>Si vous avez aimé cet article, ca serait cool d&rsquo;aller sur mon site <a href="http://www.gourmious.com">Gourmious</a> pour découvrir et partager vos plats préférés au resto.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebook oauth et Graph API avec Django</title>
		<link>https://blog.developpez.com/laurent-luce/p9325/web/facebook_oauth_et_graph_api_avec_django</link>
		<comments>https://blog.developpez.com/laurent-luce/p9325/web/facebook_oauth_et_graph_api_avec_django#comments</comments>
		<pubDate>Mon, 27 Sep 2010 18:00:14 +0000</pubDate>
		<dc:creator><![CDATA[laurent luce]]></dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Dans cet article, je vais essayer de décrire au mieux comment j&#8217;ai integré Facebook à mon site Gourmious. Le but étant pour les utilisateurs de pouvoir poster leurs commentaires sur leurs plats préférés sur Gourmious et sur Facebook en même temps. Je voulais garder l&#8217;authentification Django pour donner une option à ceux qui n&#8217;ont pas de compte Facebook ou à ceux qui ne veulent pas utiliser Gourmious avec Facebook. Je voulais aussi que tous les [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Dans cet article, je vais essayer de décrire au mieux comment j&rsquo;ai integré Facebook à mon site <a href="http://www.gourmious.com">Gourmious</a>. Le but étant pour les utilisateurs de pouvoir poster leurs commentaires sur leurs plats préférés sur Gourmious et sur Facebook en même temps.<br />
<span id="more-1"></span><br />
Je voulais garder l&rsquo;authentification Django pour donner une option à ceux qui n&rsquo;ont pas de compte Facebook ou à ceux qui ne veulent pas utiliser Gourmious avec Facebook.</p>
<p>Je voulais aussi que tous les utilisateurs de Gourmious aient un compte Gourmious et donc j&rsquo;ai décidé de ne pas autoriser l&rsquo;authentification si l&rsquo;utilisateur n&rsquo;a pas de compte Gourmious.</p>
<p>J&rsquo;ai décidé de supporter les 3 scénarios suivants:</p>
<p>1- L&rsquo;utilisateur a un compte Django, il s&rsquo;identifie en utilisant son compte Facebook, je joins son compte Django avec son compte Facebook. Cela a besoin d&rsquo;être effectué qu&rsquo;une seule fois.</p>
<p>2- L&rsquo;utilisateur n&rsquo;a pas de compte Django et essaie de s&rsquo;identifier avec son compte Facebook. Je lui demande tout d&rsquo;abord de créer un compte Django puis je joins son compte Django avec son compte Facebook.</p>
<p>3- L&rsquo;utilisateur s&rsquo;identifie avec son compte Django.</p>
<p>Facebook oauth est plus facile à intégrer que l&rsquo;ancien Facebook Connect. J&rsquo;étais très content de migrer ma plate forme vers cette nouvelle méthode.</p>
<p>On présume que vous avez déjà un serveur avec votre app Django et que vous avez créer une appli Facebook.</p>
<p>On va utiliser l&rsquo;appli Django django_facebook_oauth pour faciliter la tâche. vérifiez que vous avez simplejson d&rsquo;installé avant de continuer.</p>
<p>Facebook utilise le protocole OAuth 2.0 pour l&rsquo;authentification et l&rsquo;autorisation. Je vous conseille de lire cet article avant de continuer:<br />
<a href="http://developers.facebook.com/docs/authentication/">Facebook authentication</a></p>
<p>Récuperez le code de l&rsquo;appli Django Facebook oauth:</p>
<pre>
git clone http://github.com/dickeytk/django_facebook_oauth.git
</pre>
<p>Copiez le dossier django_facebook_oauth dans votre dossier appli Django et renommez le &lsquo;facebook&rsquo;.</p>
<p>On présume que votre dossier appli Django s&rsquo;appelle &lsquo;apps&rsquo;.</p>
<h2>Django settings.py</h2>
<p>On a besoin de faire les changements suivants:</p>
<ul>
<li>Ajoutez &lsquo;apps.facebook.backend.FacebookBackend&rsquo; à AUTHENTICATION_BACKENDS.</li>
<li>Ajoutez &lsquo;apps.facebook&rsquo; à INSTALLED_APPS</li>
<li>Ajoutez votre ID Facebook: API_ID = xxxx.</li>
<li>Ajoutez votre clé secrète Facebook: APP_SECRET = xxxx.</li>
</ul>
<h2>Django urls.py</h2>
<p>Ajoutez la ligne suivante à urlpatterns:<br />
(r&nbsp;&raquo;, include(&lsquo;apps.facebook.urls&rsquo;)),</p>
<h2>Changements dans la base de données</h2>
<p>On a besoin de créer une table pour associer l&rsquo;ID Django d&rsquo;un utilisateur avec son ID Facebook et pour sauvegarder le token de la session Facebook. Vous pouvez utiliser syncdb ou vous pouvez créer la table manuellement.</p>
<pre>
CREATE TABLE `facebook_facebookuser` (
  `id` int(11) NOT NULL auto_increment,
  `user_id` int(11) NOT NULL,
  `facebook_id` varchar(150) NOT NULL,
  `access_token` varchar(150) default NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `user_id` (`user_id`),
  UNIQUE KEY `facebook_id` (`facebook_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
</pre>
<h2>Le flux de l&rsquo;authentification Facebook</h2>
<p>1- L&rsquo;utilisateur cliques sur le bouton Facebook<br />
2- La vue &lsquo;authenticate&rsquo; de l&rsquo;appli Django Facebook est appelée<br />
3- L&rsquo;URL Graph API de Facebook est appelée avec l&rsquo;ID de votre appli Facebook, redirect uri = /authenticate, scope = &lsquo;publish_stream&rsquo; pour demander l&rsquo;autorisation de poster sur le compte Facebook de l&rsquo;utilisateur.<br />
4- La vue &lsquo;authenticate&rsquo; de l&rsquo;appli Django Facebook est appelé avec un code qui est le token pour la session Facebook.<br />
5- L&rsquo;authentification passe par la fonction authenticate() de l&rsquo;appli Django Facebook.<br />
6- Si l&rsquo;utilisateur existe dans la table facebook_facebookuser, on l&rsquo;identifie puis on renvoie vers la page d&rsquo;accueil. Si l&rsquo;utilisateur n&rsquo;est pas dans la table, on lui demande de s&rsquo;identifier avec son identifiant Django pour qu&rsquo;on puisse joindre son compte Django à son compte Facebook.</p>
<h2>Appli Django Facebook views.py</h2>
<p>J&rsquo;ai modifié views.py pour utiliser mon formulaire d&rsquo;authentification pour joindre le compte Django de l&rsquo;utilisateur à son compte Facebook au lieu d&rsquo;utiliser le formulaire inclus dans l&rsquo;appli Django Facebook.</p>
<p>Après que le token soit renvoyé et si l&rsquo;utilisateur n&rsquo;est pas dans la table Facebook, on ajoute un paramètre dans la session Django pour indiquer à la template que le formulaire d&rsquo;authentification doit être affiché pour pouvoir joindre le compte Django au compte Facebook.</p>
<pre>
if user != None:
  login(request, user)
  return HttpResponseRedirect('/')
else:
  # lignes ajoutées
  request.session['ask_to_login_facebook'] = '1'
  return HttpResponseRedirect('/')
  #return HttpResponseRedirect('/register/')
</pre>
<p>Quand l&rsquo;utilisateur s&rsquo;identifie avec son identifiant Django, on ajoute une nouvelle entrée dans la table Facebook. On a besoin de faire cela qu&rsquo;une fois. Après cela, l&rsquo;utilisateur pourra s&rsquo;identifié directement en utilisant le bouton Facebook.</p>
<p>Voici le code ajouté dans mon appli Django views.py:</p>
<pre>
# check credentials
user = authenticate(username=username, password=password)
if user is not None:
  if user.is_active:
    if 'fb_id' in request.session:
      fb_user = FacebookUser(user = user,
        facebook_id = request.session['fb_id'],
        access_token = request.session['fb_token'])
      fb_user.save()
      del request.session['fb_id']
      del request.session['fb_token']
      login(request, user)
      status = 0
    else:
      status = 1
  else:
    status = 1
    msg = _('Invalid password')
</pre>
<h2>Appli Django Facebook backend.py</h2>
<p>Juste une petite modification dans ce fichier pour ajouter dans la session le token Facebook pour pouvoir l&rsquo;utiliser dans views.py de notre appli Django.</p>
<pre>
try:
  fb_user = FacebookUser.objects.get(facebook_id = str(profile["id"]))
except FacebookUser.DoesNotExist:
  request.session['fb_id'] = profile['id']
  # ligne ajoutée
  request.session['fb_token'] = access_token
  return None
fb_user.access_token = access_token
fb_user.save()
</pre>
<h2>Template de l&rsquo;appli Django</h2>
<p>On ajoute la forme suivante à la template de notre appli Django pour afficher le bouton Facebook.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;form id=&quot;form_authenticate&quot; action=&quot;/authenticate&quot; method=&quot;POST&quot;&gt; <br />
&nbsp; &lt;p&gt;blablabla&lt;/a&gt;&lt;/p&gt; <br />
&nbsp; &lt;input id=&quot;form_authenticate_button&quot; type=&quot;image&quot; src=&quot;link_to_facebook_button&quot; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;onClick=&quot;javascript:$('#form_authenticate').submit();&quot;&gt; <br />
&lt;/form&gt;</div></div>
<p>J&rsquo;ai également ajouté une option &lsquo;Poster sur Facebook&rsquo; sur le formulaire pour poster un commentaire sur un plat. Cela donne le choix à l&rsquo;utilisateur de poster ou non le commentaire sur son compte Facebook en même temps.</p>
<h2>Poster un message sur le compte Facebook de l&rsquo;utilisateur</h2>
<p>J&rsquo;avais l&rsquo;habitude d&rsquo;utiliser le SDK Javascript de Facebook pour poster les messages. Maintenant, j&rsquo;utilise le SDK Python de Facebook du côté serveur.</p>
<p>Ajoutez le fichier facebook.py (http://github.com/facebook/python-sdk/blob/master/src/facebook.py) dans le dossier de l&rsquo;appli Django Facebook et renommez le &lsquo;facebook_sdk.py&rsquo; .</p>
<p>On appelle la fonction put_wall_post() pour poster un message sur le compte Facebook de l&rsquo;utilisateur.</p>
<p>Voila le code que j&rsquo;utilise dans views.py de mon appli Django pour préparer les paramètres nécessaires à la fonction put_wall_post() .</p>
<pre>
def post_to_facebook(request):
  try:
    fb_user = FacebookUser.objects.get(user = request.user)
    # GraphAPI est la classe dans facebook_sdp.py
    graph = GraphAPI(fb_user.access_token)
    attachment = {}
    message = 'test message'
    caption = 'test caption'
    attachment['caption'] = caption
    attachment['name'] = 'test name'
    attachment['link'] = 'link_to_picture'
    attachment['description'] = 'test description'
    graph.put_wall_post(message, attachment)
    return 0
  except:
    logging.debug('Facebook post failed')
</pre>
<p>Voila, n&rsquo;hesitez pas à ajouter des commentaires ou à m&rsquo;envoyer des questions.</p>
<p>Si vous avez aimé cet article, ça serait cool d’aller sur mon site <a href="http://www.gourmious.com">Gourmious</a> pour découvrir et partager vos plats préférés au resto.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
